packages feed

ghcup 0.1.50.2 → 0.2.1.0

raw patch · 157 files changed

+18973/−26123 lines, 157 filesdep +dhalldep +dhall-jsondep +dhall-yamldep ~aesondep ~asyncdep ~base

Dependencies added: dhall, dhall-json, dhall-yaml, either, filepattern, hspec-golden, indexed-traversable, scientific, tasty-bench, th-lift, witherable

Dependency ranges changed: aeson, async, base, brick, bytestring, containers, deepseq, directory, filepath, mtl, optparse-applicative, pretty, safe-exceptions, tar, template-haskell, text, time, unordered-containers, uri-bytestring, variant, versions, yaml

Files

CHANGELOG.md view
@@ -1,5 +1,47 @@-# Revision history for ghcup+# Version history for ghcup +## 0.2.1.0 -- 2026-05-21++### New feature++* implement **"installer DSL"** (custom tool installation) wrt [#141](https://github.com/haskell/ghcup-hs/issues/141)+  - run `ghcup config add-release-channel 3rdparty` to get access to tools like `hlint`, `ormolu`, `agda` etc.+  - refer to the [Packaging documentation](https://www.haskell.org/ghcup/packaging) for more details+  - this caused heavy changes to the internal ghcup layout and database+* major design change in the TUI (two-pane view)+  - use left/right arrow keys or tab to switch between the tool and version list+* implement **revisions**+  - these are "distributor" updates (e.g. fixes to bindists or the metadata) without requiring a proper upstream release+  - refer to the [documentation](https://www.haskell.org/ghcup/guide/#revisions) for more details+* pave the way for **OpenBSD** support wrt [#182](https://github.com/haskell/ghcup-hs/issues/182)+  - we still lack GHC bindists+* add experimental support for **Dhall metadata** wrt [#60](https://github.com/haskell/ghcup-hs/issues/60)+  - dump the Dhall schema via `ghcup generate dhall-schema`+* add `ghcup config reset` subcommand by Vladislav Sabanov+* add experimental healthcheck command `ghcup check tool ghc <ver>`+  - this may only give useful information on newly installed versions since the database needs to be populated++### Improvements and bug fixes++* Introduce `--verbosity=<LEVEL>` (0-2) option+  - `--verbose` still exists and is equivalent to `--verbosity=1`+  - ghcup won't spam the installed file list on `--verbose`/`--verbosity=1` anymore+* Store log files under `XDG_STATE_HOME` instead of `XDG_CACHE_HOME` when following XDG style by Eisuke Kawashima+* Make `--tool` and `--show-criteria` a 'many' parser, fixes [#1235](https://github.com/haskell/ghcup-hs/issues/1235)+* Ignore local cache when dlUri has a `file:` scheme, fixes [#1312](https://github.com/haskell/ghcup-hs/issues/1312)+* don't show update warnings twice (if it's the same old warning)+* Fix `ghcup whereis` on windows by only using forward slashes in the output+* lots of other things we forgot++### Breaking changes++- `cabal install <ghc-ver>` is gone, use `cabal install ghc <ghc-ver>`+- `cabal install-cabal <cabal-ver>` is gone, use `cabal install cabal <cabal-ver>`+- `ghcup compile hls --isolate=/tmp/foo` installs binaries into `/tmp/foo/bin` instead of `/tmp/foo`+- `ghcup list` may show `-rX` suffix on versions when there's a revision update+  * if you rely on version equality checks in a script and don't want to deal with parsing those, you may consider `ghcup list --show-revisions=none`+- `~/.ghcup/bin/` is now all symlinks (except for `ghcup` binary itself) and the link targets may have different shape+ ## 0.1.50.2 -- 2025-05-17  * Respect system `ld` on all platforms and disable GHCs aggressive selection of `ld.gold`, fixes [#1032](https://github.com/haskell/ghcup-hs/issues/1032)@@ -148,7 +190,7 @@ * restore proper support for FreeBSD and Linux armv7 * integrate with [errors.haskell.org](https://errors.haskell.org/index.html), wrt [#434](https://github.com/haskell/ghcup-hs/issues/434) * allow to overwrite distro detection via config wrt [#421](https://github.com/haskell/ghcup-hs/issues/421)-    - this is particularly useful for e.g. Ubuntu derivates, where ghcup doesn't pick the optimal bindist, also see the [GHCup documentation on overriding distro detection](https://www.haskell.org/ghcup/guide/#overriding-distro-detection)+    - this is particularly useful for e.g. Ubuntu derivatives, where ghcup doesn't pick the optimal bindist, also see the [GHCup documentation on overriding distro detection](https://www.haskell.org/ghcup/guide/#overriding-distro-detection) * Add proper support for mirrors wrt [#357](https://github.com/haskell/ghcup-hs/issues/357) * fix a (harmless) bug in `ghcup nuke` on windows * improvements to `ghcup add-release-channel` wrt [#708](https://github.com/haskell/ghcup-hs/issues/708)
app/ghcup/Main.hs view
@@ -1,70 +1,72 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE TypeApplications  #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell   #-}-{-# LANGUAGE QuasiQuotes       #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-}   module Main where -import           GHCup.PlanJson-+import GHCup.PlanJson #if defined(BRICK)-import           GHCup.BrickMain (brickMain)+import GHCup.BrickMain ( brickMain ) #endif--import qualified GHCup.GHC as GHC-import qualified GHCup.HLS as HLS-import           GHCup.OptParse+import GHCup.Compat.Pager+import GHCup.Download+import GHCup.Errors+import GHCup.Hardcoded.Version+import GHCup.Input.Parsers     ( resolveVersion )+import GHCup.OptParse+import GHCup.Prelude (enableAnsiSupport, decUTF8Safe')+import GHCup.Prelude.Logger+import GHCup.Prelude.String.QQ+import GHCup.Query.GHCupDirs+import GHCup.Query.Metadata+import GHCup.Query.System+import GHCup.Setup+import GHCup.Types+import GHCup.Types.Optics      hiding ( toolRequirements ) -import           GHCup.Utils.Pager-import           GHCup.Download-import           GHCup.Errors-import           GHCup.Platform-import           GHCup.Types-import           GHCup.Types.Optics      hiding ( toolRequirements )-import           GHCup.Utils-import           GHCup.Utils.Parsers (fromVersion)-import           GHCup.Prelude-import           GHCup.Prelude.Logger-import           GHCup.Prelude.String.QQ-import           GHCup.Version+import qualified GHCup.Command.Compile.GHC as GHC+import qualified GHCup.Command.Compile.HLS as HLS -import           Control.Monad (when, forM_, unless)-import           Control.Concurrent-import           Control.Concurrent.Async-import           Control.Exception.Safe+import Control.Concurrent+import Control.Concurrent.Async+import Control.Exception.Safe+import Control.Monad            ( unless ) #if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )+import Control.Monad.Fail ( MonadFail ) #endif-import           Control.Monad.Reader-import           Data.Aeson                     ( decodeStrict', Value )-import           Data.Aeson.Encode.Pretty       ( encodePretty )-import           Data.Either-import           Data.Functor-import           Data.Versions (version)-import           Data.Maybe-import           GHC.IO.Encoding-import           Data.Variant.Excepts-import           Language.Haskell.TH-import           Language.Haskell.TH.Syntax     ( Quasi(qAddDependentFile) )-import           Options.Applicative     hiding ( style )-import           Options.Applicative.Pretty.Shim ( text )-import           Prelude                 hiding ( appendFile )-import           System.Environment-import           System.Exit-import           System.IO               hiding ( appendFile )-import           System.IO.Unsafe               ( unsafeInterleaveIO )-import           Text.PrettyPrint.HughesPJClass ( prettyShow )+import Control.Monad.Reader+import Data.Aeson                      ( Value, decodeStrict' )+import Data.Aeson.Encode.Pretty        ( encodePretty )+import Data.Either+import Data.Functor+import Data.Maybe+import Data.Variant.Excepts+import Data.Versions                   ( version )+import GHC.IO.Encoding+import Language.Haskell.TH+import Language.Haskell.TH.Syntax      ( Quasi (qAddDependentFile) )+import Options.Applicative             hiding ( ParseError, style )+import Options.Applicative.Pretty.Shim ( text )+import Prelude                         hiding ( appendFile )+import System.Environment+import System.Exit+import System.FilePath                 ( (</>) )+import System.IO                       hiding ( appendFile )+import System.IO.Unsafe                ( unsafeInterleaveIO )+import Text.PrettyPrint.HughesPJClass  ( prettyShow )+import Witherable                      ( witherM ) -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-import qualified GHCup.Types                   as Types+import qualified Data.ByteString    as B+import qualified Data.Text          as T+import qualified Data.Text.Encoding as E+import qualified Data.Text.IO       as T+import qualified GHCup.Types        as Types   @@ -85,7 +87,7 @@          metaCache   = fromMaybe (fromMaybe (Types.metaCache defaultSettings) uMetaCache) optMetaCache          metaMode    = fromMaybe (fromMaybe (Types.metaMode defaultSettings) uMetaMode) optMetaMode          noVerify    = fromMaybe (fromMaybe (Types.noVerify defaultSettings) uNoVerify) optNoVerify-         verbose     = fromMaybe (fromMaybe (Types.verbose defaultSettings) uVerbose) optVerbose+         verbose     = maybe (fromMaybe (Types.verbose defaultSettings) uVerbose) Verbosity optVerbose          keepDirs    = fromMaybe (fromMaybe (Types.keepDirs defaultSettings) uKeepDirs) optKeepDirs          downloader  = fromMaybe (fromMaybe defaultDownloader uDownloader) optsDownloader          keyBindings = maybe defaultKeyBindings mergeKeys uKeyBindings@@ -95,10 +97,11 @@          platformOverride = optPlatform <|> (uPlatformOverride <|> Types.platformOverride defaultSettings)          mirrors  = fromMaybe (Types.mirrors defaultSettings) uMirrors          defGHCConfOptions  = fromMaybe (Types.defGHCConfOptions defaultSettings) uDefGHCConfOptions-         pager = case fromMaybe (fromMaybe (Types.pager defaultSettings) uPager) (flip PagerConfig Nothing <$> optPager) of+         pager = case maybe (fromMaybe (Types.pager defaultSettings) uPager) (`PagerConfig` Nothing) optPager of                    PagerConfig b Nothing -> PagerConfig b pagerCmd-                   x -> x+                   x                     -> x          guessVersion = fromMaybe (fromMaybe (Types.guessVersion defaultSettings) uGuessVersion) optGuessVersion+         buildWrapper = uBuildWrapper      in (Settings {..}, keyBindings) #if defined(INTERNAL_DOWNLOADER)    defaultDownloader = Internal@@ -112,6 +115,9 @@            bUp = fromMaybe bUp kUp          , bDown = fromMaybe bDown kDown          , bQuit = fromMaybe bQuit kQuit+         , bLeft = fromMaybe bLeft kLeft+         , bRight = fromMaybe bRight kRight+         , bTab = fromMaybe bTab kTab          , bInstall = fromMaybe bInstall kInstall          , bUninstall = fromMaybe bUninstall kUninstall          , bSet = fromMaybe bSet kSet@@ -197,17 +203,24 @@           -- logger interpreter           logfile <- runReaderT initGHCupFileLogging dirs           let loggerConfig = LoggerConfig-                { lcPrintDebug = verbose settings+                { lcPrintDebugLvl = Just ((\(Verbosity i) -> i) . verbose $ settings)                 , consoleOutter  = T.hPutStr stderr                 , fileOutter    =                     case optCommand of                       Nuke -> \_ -> pure ()-                      _ -> T.appendFile logfile+                      _    -> T.appendFile logfile                 , fancyColors = not no_color                 }-          let leanAppstate = LeanAppState settings dirs keybindings loggerConfig+          pfreq <- case platformOverride settings of+                     Just pfreq' -> return pfreq'+                     Nothing -> (flip runReaderT loggerConfig . runE @'[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound] . liftE $ platformRequest) >>= \case+                                    VRight r -> pure r+                                    VLeft e -> do+                                      runReaderT (logError $ T.pack $ prettyHFError e) loggerConfig+                                      exitWith (ExitFailure 2)+          let leanAppstate = LeanAppState settings dirs keybindings pfreq loggerConfig           let runLogger = flip runReaderT leanAppstate-          let siletRunLogger = flip runReaderT (leanAppstate { loggerConfig = loggerConfig { consoleOutter = \_ -> pure () } } :: LeanAppState)+          let silentRunLogger = flip runReaderT (leanAppstate { loggerConfig = loggerConfig { consoleOutter = \_ -> pure () } } :: LeanAppState)             -------------------------@@ -215,18 +228,9 @@           -------------------------  -          let appState = do-                pfreq <- case platformOverride settings of-                           Just pfreq' -> return pfreq'-                           Nothing -> (runLogger . runE @'[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound] . liftE $ platformRequest) >>= \case-                                          VRight r -> pure r-                                          VLeft e -> do-                                            runLogger-                                              (logError $ T.pack $ prettyHFError e)-                                            exitWith (ExitFailure 2)-+          let getAppState_and_updateCheckAction = do                 ghcupInfo <--                  ( flip runReaderT leanAppstate . runE @'[ContentLengthError, DigestError, DistroNotFound, DownloadFailed, FileDoesNotExistError, GPGError, JSONError, NoCompatibleArch, NoCompatiblePlatform, NoDownload, GHCup.Errors.ParseError, ProcessError, UnsupportedSetupCombo, StackPlatformDetectError] $ do+                  ( flip runReaderT leanAppstate . runE @'[ContentLengthError, DigestError, DistroNotFound, DownloadFailed, FileDoesNotExistError, GPGError, JSONError, NoCompatibleArch, NoCompatiblePlatform, NoDownload, GHCup.Errors.ParseError, ProcessError, UnsupportedSetupCombo, StackPlatformDetectError, UnsupportedMetadataFormat] $ do                      liftE $ getDownloadsF pfreq                   )                     >>= \case@@ -240,64 +244,54 @@                 race_ (liftIO $ runReaderT cleanupTrash s')                       (threadDelay 5000000 >> runLogger (logWarn $ "Killing cleanup thread (exceeded 5s timeout)... please remove leftover files in " <> T.pack (fromGHCupPath recycleDir) <> " manually")) -                case optCommand of-                  Nuke -> pure ()-                  Whereis _ _ -> pure ()-                  DInfo -> pure ()-                  ToolRequirements _ -> pure ()-                  ChangeLog _ -> pure ()-                  UnSet _ -> pure ()-#if defined(BRICK)-                  Interactive -> pure ()-#endif-                  -- check for new tools-                  _-                    | Just False <- optVerbose -> pure ()-                    | otherwise -> lookupEnv "GHCUP_SKIP_UPDATE_CHECK" >>= \case-                         Nothing -> void . flip runReaderT s' . runE @'[TagNotFound, DayNotFound, NextVerNotFound, NoToolVersionSet] $ do-                           newTools <- lift checkForUpdates-                           forM_ newTools $ \newTool@(t, l) -> do-                             -- https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/283-                             alreadyInstalling' <- alreadyInstalling optCommand newTool-                             when (not alreadyInstalling') $-                               case t of-                                 GHCup -> runLogger $-                                            logWarn ("New GHCup version available: "-                                              <> tVerToText l-                                              <> ". To upgrade, run 'ghcup upgrade'")-                                 _ -> runLogger $-                                        logWarn ("New "-                                          <> T.pack (prettyShow t)-                                          <> " version available. "-                                          <> "If you want to install this latest version, run 'ghcup install "-                                          <> T.pack (prettyShow t)-                                          <> " "-                                          <> tVerToText l-                                          <> "'")-                         Just _ -> pure ()+                let updateCheckAction+                      | Just 0 <- optVerbose = pure ()+                      | otherwise = void . flip runReaderT s' . runE @'[TagNotFound, DayNotFound, NextVerNotFound, NoToolVersionSet, ParseError] $ liftIO (lookupEnv "GHCUP_SKIP_UPDATE_CHECK") >>= \case+                          Nothing -> do+                            newTools <- lift checkForUpdates+                            warnMsg' <- fmap (T.intercalate "\n") $ flip witherM newTools $ \newTool@(t, l) -> do+                              -- https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/283+                              alreadyInstalling' <- alreadyInstalling optCommand newTool+                              if alreadyInstalling'+                              then pure Nothing+                              else+                                pure $ Just $+                                  case t of+                                    Tool "ghcup" ->  "New GHCup version available: "+                                                 <> T.pack (prettyShow l)+                                                 <> ". To upgrade, run 'ghcup upgrade'"+                                    _ -> "New "+                                             <> T.pack (prettyShow t)+                                             <> " version available. "+                                             <> "If you want to install this latest version, run 'ghcup install "+                                             <> T.pack (prettyShow t)+                                             <> " "+                                             <> T.pack (prettyShow l) -                -- TODO: always run for windows-                siletRunLogger (flip runReaderT s' $ runE ensureShimGen) >>= \case+                            let warnMsg = warnMsg' <> "'\nTo skip this check in the future, export GHCUP_SKIP_UPDATE_CHECK=1"+                            let warnFile = fromGHCupPath cacheDir </> "ghcup_update_check"+                            prevWarn <- try @_ @SomeException $ liftIO $ T.readFile warnFile+                            if either (const Nothing) Just prevWarn == Just warnMsg+                            then pure ()+                            else do+                              liftIO $ T.writeFile warnFile warnMsg+                              lift $ logWarn warnMsg+                          Just _ -> do+                            logDebug "GHCUP_SKIP_UPDATE_CHECK is set, skipping update check"+                            pure ()++                silentRunLogger (flip runReaderT s' $ runE ensureShimGen) >>= \case                   VRight _ -> pure ()                   VLeft e -> do                     runLogger                       (logError $ T.pack $ prettyHFError e)                     exitWith (ExitFailure 30)-                pure s' +                pure (s', updateCheckAction) -#if defined(IS_WINDOWS)-              -- FIXME: windows needs 'ensureGlobalTools', which requires-              -- full appstate-              runLeanAppState = runAppState-#else-              runLeanAppState = flip runReaderT leanAppstate-#endif-              runAppState action' = do-                s' <- liftIO appState-                runReaderT action' s'  +           -----------------           -- Run command --           -----------------@@ -305,30 +299,34 @@           res <- case optCommand of #if defined(BRICK)             Interactive -> do-              s' <- appState-              liftIO $ brickMain s' >> pure ExitSuccess+              (appState, _) <- liftIO $ getAppState_and_updateCheckAction+              liftIO $ brickMain appState >> pure ExitSuccess #endif-            Install installCommand     -> install installCommand settings appState runLogger-            InstallCabalLegacy iopts   -> install (Left (InstallCabal iopts)) settings appState runLogger-            Test testCommand           -> test testCommand settings appState runLogger-            Set setCommand             -> set setCommand settings runAppState runLeanAppState runLogger-            UnSet unsetCommand         -> unset unsetCommand runLeanAppState runLogger-            List lo                    -> list lo no_color (pager settings) runAppState-            Rm rmCommand               -> rm rmCommand runAppState runLogger-            DInfo                      -> dinfo runAppState runLogger-            Compile compileCommand     -> compile compileCommand settings dirs runAppState runLogger-            Config configCommand       -> config configCommand settings userConf keybindings runLogger+            Install installCommand     -> install installCommand settings (getAppState_and_updateCheckAction, leanAppstate)+            Test testCommand           -> test testCommand settings (getAppState_and_updateCheckAction, leanAppstate)+            Set setCommand             -> set setCommand settings (getAppState_and_updateCheckAction, leanAppstate)+            UnSet unsetCommand         -> unset unsetCommand (getAppState_and_updateCheckAction, leanAppstate)+            List lo                    -> list lo no_color (pager settings) (getAppState_and_updateCheckAction, leanAppstate)+            Rm rmCommand               -> rm rmCommand (getAppState_and_updateCheckAction, leanAppstate)+            DInfo                      -> dinfo (getAppState_and_updateCheckAction, leanAppstate)+            Compile compileCommand     -> compile compileCommand settings dirs (getAppState_and_updateCheckAction, leanAppstate)+            Config configCommand       -> config configCommand settings userConf keybindings (getAppState_and_updateCheckAction, leanAppstate)             Whereis whereisOptions-                    whereisCommand     -> whereis whereisCommand whereisOptions settings runAppState leanAppstate runLogger-            Upgrade uOpts force' fatal -> upgrade uOpts force' fatal dirs runAppState runLogger-            ToolRequirements topts     -> toolRequirements topts runAppState runLogger-            ChangeLog changelogOpts    -> changelog changelogOpts runAppState runLogger-            Nuke                       -> nuke appState runLogger-            Prefetch pfCom             -> prefetch pfCom settings runAppState runLogger-            GC gcOpts                  -> gc gcOpts runAppState runLogger-            Run runCommand             -> run runCommand settings appState leanAppstate runLogger+                    whereisCommand     -> whereis whereisCommand whereisOptions settings (getAppState_and_updateCheckAction, leanAppstate)+            Upgrade uOpts force' fatal -> upgrade uOpts force' fatal dirs (getAppState_and_updateCheckAction, leanAppstate)+            ToolRequirements topts     -> toolRequirements topts (getAppState_and_updateCheckAction, leanAppstate)+            ChangeLog changelogOpts    -> changelog changelogOpts (getAppState_and_updateCheckAction, leanAppstate)+            Nuke                       -> nuke (getAppState_and_updateCheckAction, leanAppstate)+            Prefetch pfCom             -> prefetch pfCom settings (getAppState_and_updateCheckAction, leanAppstate)+            GC gcOpts                  -> gc gcOpts (getAppState_and_updateCheckAction, leanAppstate)+            Run runCommand             -> run runCommand settings (getAppState_and_updateCheckAction, leanAppstate)             PrintAppErrors             -> putStrLn allHFError >> pure ExitSuccess+            HealthCheck hcCommands     -> hc hcCommands (getAppState_and_updateCheckAction, leanAppstate)+#if defined(DHALL)+            Generate gen -> generate gen (getAppState_and_updateCheckAction, leanAppstate)+#endif +           case res of             ExitSuccess        -> pure ()             ef@(ExitFailure _) -> exitWith ef@@ -337,61 +335,60 @@   where   alreadyInstalling :: ( HasLog env-                       , MonadFail m                        , MonadReader env m                        , HasGHCupInfo env                        , HasDirs env-                       , MonadThrow m-                       , MonadIO m-                       , MonadCatch m+                       , MonadIOish m                        )                     => Command-                    -> (Tool, GHCTargetVersion)+                    -> (Tool, TargetVersionRev)                     -> Excepts                          '[ TagNotFound                           , DayNotFound                           , NextVerNotFound                           , NoToolVersionSet+                          , ParseError                           ] m Bool-  alreadyInstalling (Install (Right InstallOptions{..}))                 (GHC, ver)   = cmp' GHC instVer ver-  alreadyInstalling (Install (Left (InstallGHC InstallOptions{..})))     (GHC, ver)   = cmp' GHC instVer ver-  alreadyInstalling (Install (Left (InstallCabal InstallOptions{..})))   (Cabal, ver)    = cmp' Cabal instVer ver-  alreadyInstalling (Install (Left (InstallHLS InstallOptions{..})))     (HLS, ver)      = cmp' HLS instVer ver-  alreadyInstalling (Install (Left (InstallStack InstallOptions{..})))   (Stack, ver)    = cmp' Stack instVer ver-  alreadyInstalling (Compile (CompileGHC GHCCompileOptions{ overwriteVer = Just [S over] })) (GHC, ver)-    | Right over' <- version (T.pack over) = cmp' GHC (Just $ GHCVersion (mkTVer over')) ver+  alreadyInstalling (Install (InstallGHC InstallOptions{..}))     (Tool "ghc", ver)   = cmp' ghc instVer ver+  alreadyInstalling (Install (InstallCabal InstallOptions{..}))   (Tool "cabal", ver) = cmp' cabal instVer ver+  alreadyInstalling (Install (InstallHLS InstallOptions{..}))     (Tool "hls", ver)   = cmp' hls instVer ver+  alreadyInstalling (Install (InstallStack InstallOptions{..}))   (Tool "stack", ver) = cmp' stack instVer ver+  alreadyInstalling (Install (InstallOtherTool InstallOptionsNew{..})) (tool, ver)+    | instTool == tool = cmp' tool instVer ver+  alreadyInstalling (Compile (CompileGHC GHCCompileOptions{ overwriteVer = Just [S over] })) (ghc', ver)+    | Right over' <- version (T.pack over) = cmp' ghc' (Just $ GHCVersion (mkTVer over' `TargetVersionReq` Nothing)) ver     | otherwise = pure False   alreadyInstalling (Compile (CompileGHC GHCCompileOptions{ targetGhc = GHC.SourceDist tver }))-    (GHC, ver)   = cmp' GHC (Just $ ToolVersion tver) ver-  alreadyInstalling (Compile (CompileHLS HLSCompileOptions{ overwriteVer = Just [S over] })) (HLS, ver)-    | Right over' <- version (T.pack over) = cmp' HLS (Just $ ToolVersion over') ver+    (Tool "ghc", ver)   = cmp' ghc (Just $ ToolVersion (tver `VersionReq` Nothing)) ver+  alreadyInstalling (Compile (CompileHLS HLSCompileOptions{ overwriteVer = Just [S over] })) (hls', ver)+    | Right over' <- version (T.pack over) = cmp' hls' (Just $ ToolVersion (over' `VersionReq` Nothing)) ver     | otherwise = pure False   alreadyInstalling (Compile (CompileHLS HLSCompileOptions{ targetHLS = HLS.SourceDist tver }))-    (HLS, ver)   = cmp' HLS (Just $ ToolVersion tver) ver+    (Tool "hls", ver)   = cmp' hls (Just $ ToolVersion (tver `VersionReq` Nothing)) ver   alreadyInstalling (Compile (CompileHLS HLSCompileOptions{ targetHLS = HLS.HackageDist tver }))-    (HLS, ver)   = cmp' HLS (Just $ ToolVersion tver) ver-  alreadyInstalling (Upgrade {}) (GHCup, _) = pure True+    (Tool "hls", ver)   = cmp' hls (Just $ ToolVersion (tver `VersionReq` Nothing)) ver+  alreadyInstalling (Upgrade {}) (Tool "ghcup", _) = pure True   alreadyInstalling _ _ = pure False    cmp' :: ( HasLog env-          , MonadFail m           , MonadReader env m           , HasGHCupInfo env           , HasDirs env-          , MonadThrow m-          , MonadIO m-          , MonadCatch m+          , MonadIOish m           )        => Tool        -> Maybe ToolVersion-       -> GHCTargetVersion+       -> TargetVersionRev        -> Excepts             '[ TagNotFound              , DayNotFound              , NextVerNotFound              , NoToolVersionSet+             , ParseError              ] m Bool-  cmp' tool instVer ver = do-    (v, _) <- liftE $ fromVersion instVer GLax tool-    pure (v == ver)+  cmp' tool instVer TargetVersionRev{..} = do+    GHCupInfo { _ghcupDownloads = dls } <- getGHCupInfo+    (TargetVersionReq v mRev) <- liftE $ resolveVersion instVer GLax tool+    let rev = fromMaybe (maybe 0 (\(_, i, _) -> i) $ getRev dls tool v Nothing) mRev+    pure (v == _tvrTargetVer && _tvrRev == rev) 
+ bench/Bench.hs view
@@ -0,0 +1,13 @@+module Main (main) where++import           Test.Tasty.Bench+import qualified BenchList+import qualified BenchParse+++main :: IO ()+main = do+  defaultMain [ BenchParse.benchMark+              , BenchList.benchMark+              ]+
+ bench/BenchList.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeApplications #-}++module BenchList (benchMark) where++import BenchSetup++import GHCup.Command.List+import GHCup.Errors+import GHCup.Types++import Control.Monad.Reader (runReaderT)+import Data.Maybe+import Data.Variant.Excepts+import Prelude hiding ( appendFile )+import Test.Tasty.Bench+import Data.Text (Text)+import Data.Versions (Version)++import qualified Data.Map.Strict as Map+++benchMark :: Benchmark+benchMark =+  bgroup "GHCup.Commands.List"+    [ bgroup "ST"+       [ env (getListInfoArgs ["data/bench/ghcup-cross-0.1.0.yaml"])           (bench "cross"   . nf listVersionsB)+       , env (getListInfoArgs ["data/bench/ghcup-0.1.0.yaml"])                 (bench "def"     . nf listVersionsB)+       , env (getListInfoArgs ["data/bench/ghcup-nightlies-2025-0.0.7.yaml"])  (bench "nightly" . nf listVersionsB)+       , env (getListInfoArgs ["data/bench/ghcup-nightlies-2025-0.0.7.yaml"+                              ,"data/bench/ghcup-0.1.0.yaml"+                              ,"data/bench/ghcup-cross-0.1.0.yaml"+                              ,"data/bench/ghcup-prereleases-0.1.0.yaml"+                              ,"data/bench/ghcup-3rdparty-0.1.0.yaml"+                              ])                                               (bench "all" . nf listVersionsB)+       ]+    , bgroup "IO"+        [ env (getAppState ["data/bench/ghcup-cross-0.1.0.yaml"])           (bench "cross"   . nfAppIO listVersionsA)+        , env (getAppState ["data/bench/ghcup-0.1.0.yaml"])                 (bench "def"     . nfAppIO listVersionsA)+        , env (getAppState ["data/bench/ghcup-nightlies-2025-0.0.7.yaml"])  (bench "nightly" . nfAppIO listVersionsA)+        , env (getAppState ["data/bench/ghcup-nightlies-2025-0.0.7.yaml"+                           ,"data/bench/ghcup-0.1.0.yaml"+                           ,"data/bench/ghcup-cross-0.1.0.yaml"+                           ,"data/bench/ghcup-prereleases-0.1.0.yaml"+                           ,"data/bench/ghcup-3rdparty-0.1.0.yaml"+                           ])                                               (bench "all" . nfAppIO listVersionsA)+        ]+    ]++listVersionsA :: AppState -> IO ToolListResult+listVersionsA s' = do+  VRight r <- flip runReaderT s' . runE @'[ParseError] $ listVersions+    Nothing     -- tools+    []          -- list criteria+    ShowUpdates -- showRevisions+    False       -- hideOld+    True        -- showNightly+    (Nothing, Nothing)+  pure r++listVersionsB :: (GHCupDownloads, PlatformRequest, Map.Map Tool (Map.Map (Maybe Text) ([VersionRev], Maybe VersionRev)), [Version]) -> ToolListResult+listVersionsB (dls, pfreq, instTools, hlsGHCs) =+  listVersions' dls pfreq instTools hlsGHCs+    Nothing     -- tools (need to sync with getListInfoArgs)+    []          -- list criteria+    ShowUpdates -- showRevisions+    False       -- hideOld+    True        -- showNightly+    (Nothing, Nothing)+
+ bench/BenchParse.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}++module BenchParse (benchMark) where++import BenchSetup++import Prelude hiding ( appendFile )+import Test.Tasty.Bench++import qualified Data.ByteString as BS+++benchMark :: Benchmark+benchMark =+  bgroup "Parse metadata"+     [ env (BS.readFile "data/bench/ghcup-cross-0.1.0.yaml")           (bench "cross"   . nfAppIO parseGHCupInfo')+     , env (BS.readFile "data/bench/ghcup-0.1.0.yaml")                 (bench "def"     . nfAppIO parseGHCupInfo')+     , env (BS.readFile "data/bench/ghcup-nightlies-2025-0.0.7.yaml")  (bench "nightly" . nfAppIO parseGHCupInfo')+     ]+
+ bench/BenchSetup.hs view
@@ -0,0 +1,86 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeApplications #-}+module BenchSetup where++import GHCup.Download+import GHCup.Errors+import GHCup.Prelude+import GHCup.Query.GHCupDirs+import GHCup.Types++import Control.DeepSeq (force)+import Control.Monad (forM)+import Control.Monad.Reader (runReaderT)+import Control.Exception (displayException, evaluate)+import Data.Maybe+import Data.Yaml (decodeFileEither, decodeEither')+import Data.Variant.Excepts+import Data.Versions (Version)+import Prelude hiding ( appendFile )+import Data.ByteString (ByteString)+import Data.Text (Text)+import GHCup.Types.Optics (getPlatformReq, getGHCupInfo)++import qualified Data.Map.Strict as Map+import GHCup.Query.DB+import GHCup.Query.DB.HLS+import Control.Monad.Trans (lift)++type DownloadErrors = '[ContentLengthError, DigestError, DistroNotFound, DownloadFailed, FileDoesNotExistError, GPGError, JSONError, NoCompatibleArch, NoCompatiblePlatform, NoDownload, GHCup.Errors.ParseError, ProcessError, UnsupportedSetupCombo, StackPlatformDetectError, UnsupportedMetadataFormat]++readGHCupInfo :: [FilePath] -> IO [NewURLSource]+readGHCupInfo fps =+  forM fps $ \fp -> do+    ghcupInfo <- either (fail . displayException) pure =<< decodeFileEither fp+    evaluate $ force $ NewGHCupInfo ghcupInfo++parseGHCupInfo' :: ByteString -> IO GHCupInfo+parseGHCupInfo' bs = do+  ghcupInfo <- either (fail . displayException) pure $ decodeEither' bs+  evaluate $ force ghcupInfo++getAppState :: [FilePath] -> IO AppState+getAppState fps = do+  infos <- readGHCupInfo fps+  spawnAppState infos++getListInfoArgs ::+     [FilePath]+  -> IO (GHCupDownloads, PlatformRequest, Map.Map Tool (Map.Map (Maybe Text) ([VersionRev], Maybe VersionRev)), [Version])+getListInfoArgs fps = do+  s' <- getAppState fps+  VRight r <- flip runReaderT s' . runE @'[ParseError] $ do+    GHCupInfo { _ghcupDownloads = dls } <- getGHCupInfo+    pfreq <- lift getPlatformReq+    instTools <- getAllInstalledTools Nothing+    hlsGHCs <- let hlsSet = do+                     hlsMap <- instTools Map.!? hls+                     (_, mSet) <- hlsMap Map.!? Nothing+                     mSet+               in case hlsSet of+                 Just VersionRev{..} -> do+                   getHLSGHCs _vrVersion+                 Nothing -> pure []+    pure (dls, pfreq, instTools, hlsGHCs)+  pure r++spawnAppState :: [NewURLSource] -> IO AppState+spawnAppState infos = do+  dirs <- getAllDirs+  let loggerConfig = LoggerConfig+        { lcPrintDebugLvl = Nothing+        , consoleOutter  = mempty+        , fileOutter    = mempty+        , fancyColors = False+        }+  let pfreq = PlatformRequest A_64 Darwin Nothing+  let settings = defaultSettings { urlSource = infos }+  let keybindings = defaultKeyBindings+  let leanAppstate = LeanAppState settings dirs keybindings pfreq loggerConfig++  VRight ghcupInfo <- flip runReaderT leanAppstate . runE @DownloadErrors $ do liftE $ getDownloadsF pfreq++  let s' = AppState settings dirs keybindings ghcupInfo pfreq loggerConfig+  evaluate (force s')+
data/config.yaml view
@@ -13,6 +13,21 @@ # whether/how to do gpg verification gpg-setting: GPGNone # GPGStrict | GPGLax | GPGNone +# A wrapper around configure/make+# Can be used to sandbox untrusted build systems, e.g.:+#+# build-wrapper: null+#   cmd: bwrap+#   cmdArgs:+#     [ --ro-bind, /, /+#     , --bind, /home/wurst/.ghcup, /home/wurst/.ghcup+#     , --bind, /home/wurst/.cabal, /home/wurst/.cabal+#     , --dev, /dev+#     , --proc, /proc+#     , --tmpfs, /tmp+#     ]+build-wrapper: null+ # TUI key bindings, # see https://hackage.haskell.org/package/vty-5.31/docs/Graphics-Vty-Input-Events.html#t:Key # for possible values.@@ -26,6 +41,12 @@     KUp: []   down:     KDown: []+  left:+    KLeft: []+  right:+    KRight: []+  tab:+    KChar: '\t'   quit:     KChar: 'q'   install:
ghcup.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.4 name:               ghcup-version:            0.1.50.2+version:            0.2.1.0 license:            LGPL-3.0-only license-file:       LICENSE copyright:          Julian Ospald 2024@@ -36,11 +36,11 @@   test/ghcup-test/data/file   test/ghcup-test/golden/unix/GHCupInfo.json -tested-with: GHC==9.6.6-           , GHC==9.4.8-           , GHC==9.2.8-           , GHC==9.0.2-           , GHC==8.10.7+tested-with: GHC==9.14.1+           , GHC==9.12.4+           , GHC==9.10.3+           , GHC==9.8.4+           , GHC==9.6.7  source-repository head   type:     git@@ -82,31 +82,77 @@   default:     False   manual:      True +flag dhall+  description: Add support for dhall encoded metadata+  default:     True+  manual:      True++flag dhall-tests+  description: Run dhall tests depedning on dhall-yaml/dhall-json+  default:     True+  manual:      False+ common common-ghc-options   ghc-options:     -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns     -fwarn-incomplete-record-updates -Werror=incomplete-patterns +common common-extensions+  default-extensions:+    DeriveGeneric+    LambdaCase+    MultiWayIf+    NamedFieldPuns+    PackageImports+    QuasiQuotes+    RecordWildCards+    ScopedTypeVariables+    StrictData+    TupleSections+    TypeApplications+    TypeFamilies+    ViewPatterns++common common-language+  default-language: Haskell2010++common platform-ifdefs+  if os(freebsd)+    cpp-options: -DIS_FREEBSD++  if os(windows)+    cpp-options: -DIS_WINDOWS+ common app-common-depends   import: common-ghc-options+  import: common-extensions+  import: common-language+  import: platform-ifdefs +  if flag(dhall)+    cpp-options: -DDHALL+    build-depends:+        dhall  ^>=1.42+      , either ^>=5.0.3+   build-depends:-    , aeson                  >=1.4+    , aeson                   >=1.4     , aeson-pretty           ^>=0.8.8     , async                  ^>=2.2.3     , attoparsec             ^>= 0.14-    , base                   >=4.12     && <5-    , bytestring             >=0.10     && <0.13+    , base                    >=4.12 && <5+    , bytestring              >=0.10 && <0.13     , containers             ^>=0.6 || ^>=0.7     , deepseq                ^>=1.4 || ^>=1.5 || ^>=1.6     , directory              ^>=1.3.6.0-    , filepath               >=1.4.101.0+    , filepath                >=1.4.101.0+    , indexed-traversable    ^>=0.1.4     , variant                ^>=1.0-    , megaparsec             >=8.0.0    && <9.8+    , megaparsec              >=8.0.0 && <9.8     , mtl                    ^>=2.2 || ^>=2.3-    , optics                ^>=0.4-    , optparse-applicative   >=0.15.1.0 && <0.19-    , pretty                 ^>=1.1.3.1+    , optics                 ^>=0.4+    , optparse-applicative    >=0.15.1.0 && <0.20+    , pretty                 ^>=1.1.3.6     , pretty-terminal        ^>=0.1.0.0     , process                ^>=1.6.11.0     , resourcet              ^>=1.2.2 || ^>=1.3@@ -114,15 +160,16 @@     , safe-exceptions        ^>=0.1     , tagsoup                ^>=0.14     , transformers           ^>=0.5 || ^>=0.6-    , template-haskell       >=2.7      && <2.24+    , template-haskell        >=2.7 && <2.25     , temporary              ^>=1.3     , text                   ^>=2.0 || ^>=2.1-    , time                   >=1.9.3    && <1.15+    , time >=1.9.3 && <1.17     , unordered-containers   ^>=0.2-    , uri-bytestring         ^>=0.4.0.0+    , uri-bytestring         ^>=0.4.0.1     , utf8-string            ^>=1.0-    , vector                 >=0.12     && <0.14-    , versions               >=6.0.5      && <6.1+    , vector                  >=0.12 && <0.14+    , versions                >=6.0.5 && <6.1+    , witherable              >=0.4 && <0.6    if flag(yaml-streamly)     build-depends:@@ -131,10 +178,19 @@     build-depends:         yaml ^>=0.11.0 +  if os(windows)+    build-depends:+      , process  ^>=1.6.11.0+      , Win32    >=2.10+  else+    build-depends:+      , unix             ^>=2.7 || ^>=2.8+      , unix-bytestring  ^>=0.4+   if flag(tar)     cpp-options:   -DTAR     build-depends:-        tar ^>=0.6.0.0+        tar ^>=0.7.0.0       , zip ^>=2.0.0 || ^>=2.1.0    else@@ -143,118 +199,103 @@ library   import:             app-common-depends   exposed-modules:-    GHCup-    GHCup.Cabal+    GHCup.Builder     GHCup.CabalConfig+    GHCup.Command.Compile.GHC+    GHCup.Command.Compile.HLS+    GHCup.Command.Install+    GHCup.Command.Install.LowLevel+    GHCup.Command.List+    GHCup.Command.Nuke+    GHCup.Command.DebugInfo+    GHCup.Command.Upgrade+    GHCup.Command.Whereis+    GHCup.Command.GC+    GHCup.Command.HealthCheck+    GHCup.Command.Prefetch+    GHCup.Command.Rm+    GHCup.Command.Set+    GHCup.Command.Test.GHC+    GHCup.Compat.Pager+    GHCup.Compat.Terminal     GHCup.Download-    GHCup.Download.Utils     GHCup.Errors-    GHCup.GHC-    GHCup.HLS-    GHCup.List-    GHCup.Platform+    GHCup.Hardcoded.URLs+    GHCup.Hardcoded.Version+    GHCup.Input.Parsers+    GHCup.Input.Parsers.URI+    GHCup.Input.Prompts+    GHCup.Input.SymlinkSpec+    GHCup.Legacy.Cabal+    GHCup.Legacy.HLS+    GHCup.Legacy.Stack+    GHCup.Legacy.Utils     GHCup.PlanJson     GHCup.Prelude     GHCup.Prelude.Attoparsec     GHCup.Prelude.File     GHCup.Prelude.File.Search     GHCup.Prelude.Internal+    GHCup.Prelude.JSON     GHCup.Prelude.Logger     GHCup.Prelude.Logger.Internal     GHCup.Prelude.MegaParsec     GHCup.Prelude.Process     GHCup.Prelude.String.QQ+    GHCup.Prelude.Version     GHCup.Prelude.Version.QQ-    GHCup.Prompts-    GHCup.Requirements-    GHCup.Stack+    GHCup.Query+    GHCup.Query.DB+    GHCup.Query.DB.HLS+    GHCup.Query.GHCupDirs+    GHCup.Query.Metadata+    GHCup.Query.Symlink+    GHCup.Query.System+    GHCup.Setup+    GHCup.System.Cmd+    GHCup.System.Directory     GHCup.Types+    GHCup.Types.Dhall     GHCup.Types.JSON     GHCup.Types.JSON.MapIgnoreUnknownKeys     GHCup.Types.JSON.Utils     GHCup.Types.JSON.Versions     GHCup.Types.Optics     GHCup.Types.Stack-    GHCup.Utils-    GHCup.Utils.Dirs-    GHCup.Utils.Tar-    GHCup.Utils.Tar.Types-    GHCup.Utils.URI-    GHCup.Utils.Output-    GHCup.Utils.Pager-    GHCup.Utils.Parsers-    GHCup.Version+    GHCup.Types.Tar+    GHCup.Unpack+    GHCup.Warnings    hs-source-dirs:     lib   other-modules:      Paths_ghcup   autogen-modules:    Paths_ghcup-  default-language:   Haskell2010-  default-extensions:-    DeriveGeneric-    LambdaCase-    MultiWayIf-    NamedFieldPuns-    PackageImports-    QuasiQuotes-    RecordWildCards-    ScopedTypeVariables-    StrictData-    TupleSections-    TypeApplications-    TypeFamilies-    ViewPatterns    build-depends:-    , aeson                 >=1.4-    , async                 >=0.8        && <2.3-    , attoparsec            ^>= 0.14-    , base                  >=4.12       && <5     , base16-bytestring     >=0.1.1.6    && <1.1     , binary                ^>=0.8.6.0 || ^>=0.9 || ^>=0.10-    , bytestring            >=0.10       && <0.13     , bz2                   ^>=1.0.1.1     , Cabal                 ^>=3.0.0.0 || ^>=3.2.0.0 || ^>=3.4.0.0 || ^>=3.6.0.0 || ^>=3.8.0.0 || ^>= 3.10.0.0 || ^>= 3.12.0.0 || ^>= 3.14.0.0     , Cabal-syntax          ^>=3.6.0.0 || ^>=3.8.0.0 || ^>= 3.10.0.0 || ^>= 3.12.0.0 || ^>= 3.14.0.0     , case-insensitive      ^>=1.2.1.0     , casing                ^>=0.1.4.1-    , containers            ^>=0.6 || ^>=0.7     , conduit               ^>=1.3     , conduit-extra         ^>=1.3     , cryptohash-sha256     ^>=0.11.101.0-    , deepseq               ^>=1.4 || ^>=1.5 || ^>=1.6-    , directory             ^>=1.3.6.0     , disk-free-space       ^>=0.1.0.1     , exceptions            ^>=0.10-    , filepath              >=1.4.101.0+    , filepattern           ^>=0.1.3     , file-uri              ^>=0.1.0.0-    , variant                ^>=1.0     , xz                    ^>=5.6.3-    , megaparsec            >=8.0.0      && <9.8-    , mtl                   ^>=2.2 || ^>=2.3-    , optics                ^>=0.4     , os-release            ^>=1.0.0     , parsec-    , pretty                ^>=1.1.3.1-    , pretty-terminal       ^>=0.1.0.0     , regex-posix           ^>=0.96-    , resourcet             ^>=1.2.2 || ^>=1.3     , retry                 >=0.8.1.2    && <0.10-    , safe                  ^>=0.3.18-    , safe-exceptions       ^>=0.1+    , scientific     , split                 ^>=0.2.3.4     , strict-base           ^>=0.4-    , template-haskell       >=2.7      && <2.24-    , temporary             ^>=1.3     , terminal-size         ^>=0.3.3-    , text                  ^>=2.0 || ^>=2.1-    , time                  >=1.9.3      && <1.15-    , transformers          ^>=0.5 || ^>=0.6+    , th-lift               ^>=0.8.7     , unliftio-core         ^>=0.2.0.1-    , unordered-containers  ^>=0.2.10.0-    , uri-bytestring        ^>=0.4.0.0-    , utf8-string           ^>=1.0-    , vector                 >=0.12     && <0.14-    , versions               >=6.0.5      && <6.1     , word8                 ^>=0.1.3     , zlib                  ^>=0.6.2.2 || ^>=0.7 @@ -265,15 +306,6 @@     build-depends:         yaml ^>=0.11.0 -  if flag(tar)-    cpp-options:   -DTAR-    build-depends:-        tar ^>=0.6.0.0-      , zip ^>=2.0.0 || ^>=2.1.0--  else-    build-depends: libarchive ^>=3.0.3.0-   if (flag(internal-downloader) && !os(windows))     exposed-modules: GHCup.Download.IOStreams     cpp-options:     -DINTERNAL_DOWNLOADER@@ -284,16 +316,12 @@       , terminal-progress-bar  >=0.4.1    if os(windows)-    cpp-options:     -DIS_WINDOWS     other-modules:       GHCup.Prelude.File.Windows       GHCup.Prelude.Windows      -- GHCup.OptParse.Run uses this     exposed-modules: GHCup.Prelude.Process.Windows-    build-depends:-      , process  ^>=1.6.11.0-      , Win32    >=2.10    else     other-modules:@@ -306,13 +334,10 @@     include-dirs:     cbits     install-includes: dirutils.h     c-sources:        cbits/dirutils.c-    build-depends:-      , unix             ^>=2.7 || ^>=2.8-      , unix-bytestring  ^>=0.4    if flag(tui)     cpp-options:   -DBRICK-    build-depends: vty ^>=6.0 || ^>=6.1 || ^>=6.2+    build-depends: vty ^>=6.0 || ^>=6.1 || ^>=6.2 || ^>=6.3 || ^>=6.4    if (flag(strict-metadata-parsing))     cpp-options:     -DSTRICT_METADATA_PARSING@@ -325,12 +350,15 @@     GHCup.OptParse.Common     GHCup.OptParse.Compile     GHCup.OptParse.Config-    GHCup.OptParse.DInfo+    GHCup.OptParse.DebugInfo     GHCup.OptParse.GC+    GHCup.OptParse.Generate+    GHCup.OptParse.HealthCheck     GHCup.OptParse.Install     GHCup.OptParse.List     GHCup.OptParse.Nuke     GHCup.OptParse.Prefetch+    GHCup.OptParse.Reset     GHCup.OptParse.Rm     GHCup.OptParse.Run     GHCup.OptParse.Set@@ -342,16 +370,6 @@     Options.Applicative.Pretty.Shim    hs-source-dirs:     lib-opt-  default-language:   Haskell2010-  default-extensions:-    LambdaCase-    MultiWayIf-    NamedFieldPuns-    PackageImports-    RecordWildCards-    ScopedTypeVariables-    StrictData-    TupleSections    build-depends:      ghcup @@ -361,12 +379,6 @@   if flag(tui)     cpp-options:   -DBRICK -  if os(windows)-    cpp-options: -DIS_WINDOWS--  else-    build-depends:  unix ^>=2.7 || ^>=2.8- library ghcup-tui   import:             app-common-depends   exposed-modules:@@ -374,10 +386,10 @@     GHCup.Brick.Widgets.Navigation     GHCup.Brick.Widgets.Tutorial     GHCup.Brick.Widgets.KeyInfo-    GHCup.Brick.Widgets.SectionList+    GHCup.Brick.Widgets.ToolInfo     GHCup.Brick.Widgets.Menu     GHCup.Brick.Widgets.Menus.Context-    GHCup.Brick.Widgets.Menus.AdvanceInstall+    GHCup.Brick.Widgets.Menus.AdvancedInstall     GHCup.Brick.Widgets.Menus.CompileGHC     GHCup.Brick.Widgets.Menus.CompileHLS     GHCup.Brick.Actions@@ -387,46 +399,20 @@     GHCup.Brick.Common    hs-source-dirs:     lib-tui-  default-language:   Haskell2010-  default-extensions:-    LambdaCase-    MultiWayIf-    NamedFieldPuns-    PackageImports-    RecordWildCards-    ScopedTypeVariables-    StrictData-    TupleSections    build-depends:     , ghcup-    , brick         >=2.1 && <2.8-    , vty           ^>=6.0 || ^>=6.1 || ^>=6.2+    , brick >=2.1 && <2.13+    , vty           ^>=6.0 || ^>=6.1 || ^>=6.2 || ^>=6.3 || ^>=6.4    if !flag(tui)     buildable: False -  if os(windows)-    cpp-options: -DIS_WINDOWS--  else-    build-depends:  unix ^>=2.7 || ^>=2.8- executable ghcup   import:             app-common-depends   main-is:            Main.hs    hs-source-dirs:     app/ghcup-  default-language:   Haskell2010-  default-extensions:-    LambdaCase-    MultiWayIf-    NamedFieldPuns-    PackageImports-    RecordWildCards-    ScopedTypeVariables-    StrictData-    TupleSections    ghc-options:     -threaded@@ -442,18 +428,15 @@     cpp-options:   -DBRICK     build-depends:       , ghcup-tui-      , transformers  ^>=0.5 || ^>=0.6 -  if os(windows)-    cpp-options: -DIS_WINDOWS-  else-    build-depends: unix ^>=2.7 || ^>=2.8-   if flag(no-exe)     buildable: False  test-suite ghcup-test   import: common-ghc-options+  import: common-extensions+  import: common-language+  import: platform-ifdefs   type:               exitcode-stdio-1.0   main-is:            Main.hs   build-tool-depends: hspec-discover:hspec-discover -any@@ -466,45 +449,52 @@     GHCup.ParserSpec     Spec -  default-language:   Haskell2010-  default-extensions:-    LambdaCase-    MultiWayIf-    PackageImports-    RecordWildCards-    ScopedTypeVariables-    TupleSections-   ghc-options:     -fconstraint-solver-iterations=0 +  if flag(dhall) && flag(dhall-tests)+    cpp-options: -DDHALL+    build-depends:+        dhall  ^>=1.42+      , dhall-json ^>= 1.7.11+      , dhall-yaml ^>= 1.2.11+      , either ^>=5.0.3+   build-depends:-    , base                      >=4.12    && <5-    , bytestring                >=0.10    && <0.13+    , aeson                      >=1.4+    , aeson-pretty              ^>=0.8.8+    , base                       >=4.12    && <5+    , bytestring                 >=0.10    && <0.13     , containers                ^>=0.6 || ^>=0.7     , conduit                   ^>=1.3     , directory                 ^>=1.3.6.0-    , filepath                  >=1.4.101.0+    , filepath                   >=1.4.101.0     , generic-arbitrary         ^>=0.1.0 || ^>=0.2.2 || ^>=1.0.0     , ghcup-    , hspec                     >=2.7.10  && <2.12+    , hspec                      >=2.7.10  && <2.12+    , hspec-golden              ^>=0.2.2.0     , hspec-golden-aeson        ^>=0.9-    , megaparsec                >=8.0.0    && <9.8+    , megaparsec                 >=8.0.0    && <9.8+    , pretty                    ^>=1.1.3.6     , QuickCheck                ^>=2.14.1 || ^>=2.15     , quickcheck-arbitrary-adt  ^>=0.3.1.0     , text                      ^>=2.0 || ^>=2.1-    , time                      >=1.9.3   && <1.15-    , uri-bytestring            ^>=0.4.0.0+    , time >=1.9.3 && <1.17+    , uri-bytestring            ^>=0.4.0.1+    , yaml     , versions                   >=6.0.5      && <6.1 -  if os(windows)-    cpp-options: -DIS_WINDOWS+  if os(freebsd)+    cpp-options: -DIS_FREEBSD -  else+  if !os(windows)     build-depends: unix ^>=2.7 || ^>=2.8  test-suite ghcup-optparse-test   import: common-ghc-options+  import: common-extensions+  import: common-language+  import: platform-ifdefs   type:             exitcode-stdio-1.0   hs-source-dirs:   test/optparse-test   main-is:          Main.hs@@ -524,10 +514,6 @@     Utils     WhereisTest -  if os(windows)-    cpp-options: -DIS_WINDOWS--  default-language: Haskell2010   build-depends:     , base     , ghcup@@ -539,3 +525,36 @@     , text     , uri-bytestring     , versions++benchmark bench+  import: common-ghc-options+  import: common-extensions+  import: common-language+  import: platform-ifdefs++  main-is:          Bench.hs+  other-modules:    BenchList+                    BenchParse+                    BenchSetup+  type:             exitcode-stdio-1.0+  hs-source-dirs:   bench+  ghc-options:      -O2 "-with-rtsopts=-A32m"+  if impl(ghc >= 8.6)+    ghc-options:    -fproc-alignment=64+  build-depends:    base,+                    aeson,+                    bytestring,+                    containers,+                    directory,+                    deepseq,+                    filepath,+                    ghcup,+                    mtl,+                    safe-exceptions,+                    tasty-bench,+                    template-haskell,+                    text,+                    variant,+                    versions,+                    yaml+
lib-opt/GHCup/OptParse.hs view
@@ -2,7 +2,6 @@ {-# LANGUAGE DataKinds         #-} {-# LANGUAGE FlexibleContexts  #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TypeApplications #-} {-# LANGUAGE DuplicateRecordFields #-}  @@ -23,7 +22,11 @@   , module GHCup.OptParse.ChangeLog   , module GHCup.OptParse.Prefetch   , module GHCup.OptParse.GC-  , module GHCup.OptParse.DInfo+#if defined(DHALL)+  , module GHCup.OptParse.Generate+#endif+  , module GHCup.OptParse.HealthCheck+  , module GHCup.OptParse.DebugInfo   , module GHCup.OptParse.Nuke   , module GHCup.OptParse.ToolRequirements   , module GHCup.OptParse.Run@@ -48,17 +51,19 @@ import           GHCup.OptParse.ChangeLog import           GHCup.OptParse.Prefetch import           GHCup.OptParse.GC-import           GHCup.OptParse.DInfo+#if defined(DHALL)+import           GHCup.OptParse.Generate+#endif+import           GHCup.OptParse.HealthCheck+import           GHCup.OptParse.DebugInfo import           GHCup.OptParse.ToolRequirements import           GHCup.OptParse.Nuke  import           GHCup.Types-import           GHCup.Utils.Parsers (gpgParser, downloaderParser, keepOnParser, platformParser, parseUrlSource)+import           GHCup.Input.Parsers (gpgParser, downloaderParser, keepOnParser, platformParser) #if !MIN_VERSION_base(4,13,0) import           Control.Monad.Fail             ( MonadFail ) #endif-import           Control.Monad.Reader-import           Data.Either import           Data.Functor import           Data.Maybe import           Options.Applicative     hiding ( style )@@ -67,7 +72,7 @@ import System.Exit import System.Environment (getProgName) import System.IO-import GHCup.Utils.Pager+import GHCup.Compat.Pager import qualified Data.Text as T import Data.Function ((&)) @@ -76,7 +81,7 @@ data Options = Options   {   -- global options-    optVerbose     :: Maybe Bool+    optVerbose     :: Maybe Int   , optCache       :: Maybe Bool   , optMetaCache   :: Maybe Integer   , optMetaMode    :: Maybe MetaMode@@ -95,13 +100,12 @@   }  data Command-  = Install (Either InstallCommand InstallOptions)+  = Install InstallCommand   | Test TestCommand-  | InstallCabalLegacy InstallOptions-  | Set (Either SetCommand SetOptions)+  | Set SetCommand   | UnSet UnsetCommand   | List ListOptions-  | Rm (Either RmCommand RmOptions)+  | Rm RmCommand   | DInfo   | Compile CompileCommand   | Config ConfigCommand@@ -111,6 +115,9 @@ #endif   | ToolRequirements ToolReqOpts   | ChangeLog ChangeLogOptions+#if defined(DHALL)+  | Generate GenerateCommand+#endif   | Nuke #if defined(BRICK)   | Interactive@@ -118,14 +125,21 @@   | Prefetch PrefetchCommand   | GC GCOptions   | Run RunOptions+  | HealthCheck HealthCheckCommand   | PrintAppErrors  +toVerbosity :: Maybe Bool -> Maybe Int+toVerbosity (Just True)  = Just 1+toVerbosity (Just False) = Just 0+toVerbosity _           = Nothing + opts :: Parser Options opts =   Options-    <$> invertableSwitch "verbose" (Just 'v') False (help "Enable verbosity (default: disabled)")+    <$> (fmap toVerbosity (invertableSwitch "verbose" (Just 'v') False (help "Enable verbosity (default: disabled)"))+        <|> optional (option auto (long "verbosity" <> metavar "LEVEL" <> help "verbosity level (0 for off, 1 for 'verbose', 2 for extra)")))     <*> invertableSwitch "cache" (Just 'c') False (help "Cache downloads in ~/.ghcup/cache (default: disabled)")     <*> optional (option auto (long "metadata-caching" <> metavar "SEC" <> help "How long the yaml metadata caching interval is (in seconds), 0 to disable"))     <*> optional (option auto (long "metadata-fetching-mode" <> metavar "<Strict|Lax>" <> help "Whether to fail on metadata download failure (Strict) or fall back to cached version (Lax (default))"))@@ -140,16 +154,7 @@         )       )     <*> optional-          (option-            (eitherReader parseUrlSource)-            (  short 's'-            <> long "url-source"-            <> metavar "<URL_SOURCE|cross|prereleases|vanilla|default>"-            <> help "Alternative ghcup download info"-            <> internal-            <> completer urlSourceCompleter-            )-          )+          parseUrlSourceP     <*> (fmap . fmap) not (invertableSwitch "verify" (Just 'n') True (help "Disable tarball checksum verification (default: enabled)"))     <*> optional (option           (eitherReader keepOnParser)@@ -186,7 +191,7 @@           <> completer (listCompleter ["strict", "lax", "none"])           ))     <*> invertableSwitch "stack-setup" Nothing False (help "Use stack's setup info for discovering and installing GHC versions")-    <*> (invertableSwitch "paginate" Nothing False (help "Send output (e.g. from 'ghcup list') through pager (default: disabled)"))+    <*> invertableSwitch "paginate" Nothing False (help "Send output (e.g. from 'ghcup list') through pager (default: disabled)")     <*> invertableSwitch "guess-version" Nothing True (help "Whether to guess the full version from an incomplete tool version, e.g. GHC '9.12' resolving to '9.12.2'")     <*> com @@ -276,8 +281,8 @@       <> command            "whereis"             (info-             (   (Whereis-                     <$> (WhereisOptions <$> switch (short 'd' <> long "directory" <> help "return directory of the binary instead of the binary location"))+             (+                     (Whereis . WhereisOptions <$> switch (short 'd' <> long "directory" <> help "return directory of the binary instead of the binary location")                      <*> whereisP                  ) <**> helper              )@@ -314,6 +319,12 @@                    <> footerDoc ( Just $ text runFooter )                    )                )+      <> command+              "check"+              ( HealthCheck <$>+               info (hcP <**> helper)+                    (progDesc "Health check ghcup")+              )       <> commandGroup "Main commands:"       )     <|> subparser@@ -340,37 +351,30 @@                <$> info (configP <**> helper)                         (progDesc "Show or set config" <> footerDoc (Just $ text configFooter))                )+#if defined(DHALL)+          <> command+               "generate"+                ( Generate+                <$> (info (generateP <**> helper)+                          (progDesc "Various generation facilities related to metadata"))+                )+#endif+          <> command+               "nuke"+                (info (pure Nuke <**> helper)+                      (progDesc "Completely remove ghcup from your system"))           <> commandGroup "Other commands:"           <> hidden           )-    <|> subparser-          (  command-              "install-cabal"-              (info-                 ((InstallCabalLegacy <$> installOpts (Just Cabal)) <**> helper)-                 (  progDesc "Install or update cabal"-                 <> footerDoc (Just $ text installCabalFooter)-                 )-              )-          <> internal-          )      <|> subparser           (command-              "nuke"-               (info (pure Nuke <**> helper)-                     (progDesc "Completely remove ghcup from your system"))-           <> commandGroup "Nuclear Commands:"-           <> hidden-          )-     <|> subparser-          (command               "print-app-errors"                (info (pure PrintAppErrors <**> helper)                      (progDesc ""))            <> internal           ) --- | Handle `ParserResult`.+-- | Handle 'ParserResult'. handleParseResult' :: Maybe FilePath -> Bool -> ParserResult a -> IO a handleParseResult' _ _ (Success a) = return a handleParseResult' pagerCmd hasHelp (Failure failure) = do
lib-opt/GHCup/OptParse/ChangeLog.hs view
@@ -1,56 +1,57 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE TypeApplications  #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE TemplateHaskell   #-}-{-# LANGUAGE QuasiQuotes       #-}-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-}  module GHCup.OptParse.ChangeLog where  -import           GHCup.Types-import           GHCup.Errors-import           GHCup.OptParse.Common-import           GHCup.Prelude-import           GHCup.Prelude.Logger-import           GHCup.Prelude.String.QQ-import           GHCup.Prelude.Process (exec)+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 )+import Control.Monad.Fail ( MonadFail ) #endif-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-import           Data.Functor-import           Data.Maybe-import           Options.Applicative     hiding ( style )-import           Prelude                 hiding ( appendFile )-import           System.Exit-import           System.Process                 ( system )-import           Text.PrettyPrint.HughesPJClass ( prettyShow )--import qualified Data.Text                     as T-import Control.Exception.Safe (MonadMask)+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 GHCup.Utils-import URI.ByteString (serializeURIRef')-import Data.Char (toLower)+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+  { clOpen :: Bool+  , clTool :: Maybe Tool   , clToolVer :: Maybe ToolVersion-  } deriving (Eq, Show)+  }+  deriving (Eq, Show)   @@ -67,13 +68,7 @@     <*> optional           (option             (eitherReader-              (\s' -> case fmap toLower s' of-                "ghc"   -> Right GHC-                "cabal" -> Right Cabal-                "ghcup" -> Right GHCup-                "stack" -> Right Stack-                "hls"   -> Right HLS-                e       -> Left e+              (\s' -> Right (Tool (fmap toLower s'))               )             )             (short 't' <> long "tool" <> metavar "<ghc|cabal|hls|ghcup|stack>" <> help@@ -109,43 +104,46 @@              , MonadFail m              )           => ChangeLogOptions-          -> (forall a . ReaderT AppState m a -> m a)-          -> (ReaderT LeanAppState m () -> m ())+          -> (IO (AppState, IO ()), LeanAppState)           -> m ExitCode-changelog ChangeLogOptions{..} runAppState runLogger = do-  GHCupInfo { _ghcupDownloads = dls } <- runAppState getGHCupInfo-  let tool = fromMaybe GHC clTool-      ver' = fromMaybe-        (ToolTag Latest)-        clToolVer-      muri = getChangeLog dls tool ver'+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-      runLogger-        (logWarn $-          "Could not find ChangeLog for " <> T.pack (prettyShow tool) <> ", version " <> T.pack (prettyShow ver')-        )-      pure ExitSuccess+      lift $ logWarn $ "Could not find ChangeLog for " <> T.pack (prettyShow tool) <> ", version " <> T.pack (prettyShow treq)     Just uri -> do-      pfreq <- runAppState getPlatformReq+      pfreq <- lift getPlatformReq       let uri' = T.unpack . decUTF8Safe . serializeURIRef' $ uri       if clOpen         then do-          runAppState $-            case _rPlatform pfreq of-              Darwin  -> exec "open" [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing-              Linux _ -> exec "xdg-open" [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing-              FreeBSD -> exec "xdg-open" [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing-              OpenBSD -> 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) -> pure $ Left $ NonZeroExit xi "cmd.exe" [args]-                   ExitSuccess -> pure $ Right ()-              >>= \case-                    Right _ -> pure ExitSuccess-                    Left  e -> logError (T.pack $ prettyHFError e)-                      >> pure (ExitFailure 13)-        else liftIO $ putStrLn uri' >> pure ExitSuccess+          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 
lib-opt/GHCup/OptParse/Common.hs view
@@ -1,87 +1,99 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeApplications #-} {-# LANGUAGE NumericUnderscores #-}-{-# LANGUAGE ViewPatterns      #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}  module GHCup.OptParse.Common where  -import           GHCup-import           GHCup.CabalConfig-import           GHCup.Download-import           GHCup.Platform-import           GHCup.Types-import           GHCup.Types.Optics-import           GHCup.Utils-import qualified GHCup.Utils.Parsers as Parsers-import           GHCup.Prelude-import           GHCup.Prelude.Process-import           GHCup.Prelude.Logger+import GHCup.CabalConfig+import GHCup.Command.List+import GHCup.Download+import GHCup.Hardcoded.Version+import GHCup.Input.Parsers+import GHCup.Prelude+import GHCup.Prelude.Process+import GHCup.Query.GHCupDirs+import GHCup.Query.Metadata+import GHCup.Query.System+import GHCup.System.Directory+import GHCup.Types+import GHCup.Types.Optics -import           Control.Monad (forM, join)-import           Control.DeepSeq-import           Control.Concurrent-import           Control.Concurrent.Async-import           Control.Exception.Safe+import qualified GHCup.Input.Parsers as Parsers++import Control.Concurrent+import Control.Concurrent.Async+import Control.DeepSeq+import Control.Exception        ( evaluate )+import Control.Exception.Safe+import Control.Monad            ( forM, join ) #if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )+import Control.Monad.Fail ( MonadFail ) #endif-import           Control.Monad.Reader-import           Data.Aeson+import Control.Monad.Reader+import Data.Aeson #if MIN_VERSION_aeson(2,0,0) import qualified Data.Aeson.Key    as KM import qualified Data.Aeson.KeyMap as KM #else import qualified Data.HashMap.Strict as KM #endif-import           Data.ByteString.Lazy           ( ByteString ) import           Data.Bifunctor+import           Data.ByteString.Lazy ( ByteString ) import           Data.Char import           Data.Either import           Data.Functor-import           Data.List                      ( nub, isPrefixOf, stripPrefix )+import           Data.List            ( isPrefixOf, nub, stripPrefix ) import           Data.Maybe+import           Data.Variant.Excepts+import qualified Data.Vector          as V import           Data.Versions-import qualified Data.Vector      as V import           GHC.IO.Exception-import           Data.Variant.Excepts-import           Options.Applicative     hiding ( style )-import           Prelude                 hiding ( appendFile )-import           Safe (lastMay)-import           System.Process                  ( readProcess )+import           Options.Applicative  hiding ( style )+import           Prelude              hiding ( appendFile )+import           Safe                 ( lastMay ) import           System.FilePath-import           Text.HTML.TagSoup       hiding ( Tag )+import           System.Process       ( readProcess )+import           Text.HTML.TagSoup    hiding ( Tag ) -import qualified Data.Map.Strict               as M-import qualified Data.Text                     as T-import qualified System.FilePath.Posix         as FP-import GHCup.Version-import Control.Exception (evaluate)+import qualified Data.Map.Strict       as M+import qualified Data.Text             as T+import qualified System.FilePath.Posix as FP      --------------     --[ Parser ]--     -------------- +parseUrlSourceP :: Parser [NewURLSource]+parseUrlSourceP =+    option+      (eitherReader parseUrlSource)+      (  short 's'+      <> long "url-source"+      <> metavar "<URL_SOURCE|cross|prereleases|vanilla|default>"+      <> help "Alternative ghcup download info"+      <> completer urlSourceCompleter+      )  toolVersionTagArgument :: [ListCriteria] -> Maybe Tool -> Parser ToolVersion toolVersionTagArgument criteria tool =   argument (eitherReader (parser tool))     (metavar (mv tool)-    <> completer (tagCompleter (fromMaybe GHC tool) [])+    <> completer (tagCompleter (fromMaybe ghc tool) [])     <> foldMap (completer . versionCompleter criteria) tool)  where-  mv (Just GHC) = "GHC_VERSION|TAG|RELEASE_DATE"-  mv (Just HLS) = "HLS_VERSION|TAG|RELEASE_DATE"-  mv _          = "VERSION|TAG|RELEASE_DATE"+  mv (Just (Tool "ghc")) = "GHC_VERSION|TAG|RELEASE_DATE"+  mv (Just (Tool "hls")) = "HLS_VERSION|TAG|RELEASE_DATE"+  mv _                   = "VERSION|TAG|RELEASE_DATE" -  parser (Just GHC) = Parsers.ghcVersionTagEither-  parser Nothing    = Parsers.ghcVersionTagEither-  parser _          = Parsers.toolVersionTagEither+  parser (Just (Tool "ghc")) = Parsers.ghcVersionTagEither+  parser Nothing             = Parsers.ghcVersionTagEither+  parser _                   = Parsers.toolVersionTagEither   versionParser' :: [ListCriteria] -> Maybe Tool -> Parser Version@@ -89,9 +101,9 @@   (eitherReader (first show . version . T.pack))   (metavar "VERSION"  <> foldMap (completer . versionCompleter criteria) tool) -ghcVersionArgument :: [ListCriteria] -> Maybe Tool -> Parser GHCTargetVersion+ghcVersionArgument :: [ListCriteria] -> Maybe Tool -> Parser TargetVersion ghcVersionArgument criteria tool = argument (eitherReader Parsers.ghcVersionEither)-                                            (metavar "VERSION" <> foldMap (completer . versionCompleter criteria) tool)+                                            (metavar "VERSION" <> help "Which version to install" <> foldMap (completer . versionCompleter criteria) tool)   -- https://github.com/pcapriotti/optparse-applicative/issues/148@@ -136,6 +148,8 @@     --[ Completers ]--     ------------------ +revisionCompleter :: Completer+revisionCompleter = listCompleter ["updates", "all", "none"]  toolCompleter :: Completer toolCompleter = listCompleter ["ghc", "cabal", "hls", "stack"]@@ -178,7 +192,7 @@   compgen action' r opts = do     let cmd = unwords $ ["compgen", "-A", action'] <> opts <> ["--", requote r]     result <- tryIO $ readProcess "bash" ["-c", cmd] ""-    return . lines . either (const []) id $ result+    return . lines . fromRight [] $ result    -- | Strongly quote the string we pass to compgen.   --@@ -228,20 +242,20 @@       unescapeN = goX         where           goX ('\'' : xs) = goN xs-          goX (x : xs) = x : goX xs-          goX [] = []+          goX (x : xs)    = x : goX xs+          goX []          = []            goN ('\\' : '\'' : xs) = '\'' : goN xs-          goN ('\'' : xs) = goX xs-          goN (x : xs) = x : goN xs-          goN [] = []+          goN ('\'' : xs)        = goX xs+          goN (x : xs)           = x : goN xs+          goN []                 = []        -- Unescape an unquoted string       unescapeU = goX         where-          goX [] = []+          goX []              = []           goX ('\\' : x : xs) = x : goX xs-          goX (x : xs) = x : goX xs+          goX (x : xs)        = x : goX xs        -- Unescape a weakly quoted string       unescapeD = goX@@ -269,24 +283,25 @@ tagCompleter tool add = listIOCompleter $ do   dirs' <- liftIO getAllDirs   let loggerConfig = LoggerConfig-        { lcPrintDebug   = False+        { lcPrintDebugLvl = Nothing         , consoleOutter  = mempty         , fileOutter     = mempty         , fancyColors    = False         }-  let appState = LeanAppState-        (defaultSettings { noNetwork = True })-        dirs'-        defaultKeyBindings-        loggerConfig -  mpFreq <- flip runReaderT appState . runE $ platformRequest+  mpFreq <- flip runReaderT loggerConfig . runE $ platformRequest   forFold mpFreq $ \pfreq -> do+    let appState = LeanAppState+          (defaultSettings { noNetwork = True })+          dirs'+          defaultKeyBindings+          pfreq+          loggerConfig     mGhcUpInfo <- flip runReaderT appState . runE $ getDownloadsF pfreq     case mGhcUpInfo of       VRight ghcupInfo -> do         let allTags = filter (/= Old)-              $ _viTags =<< M.elems (availableToolVersions (_ghcupDownloads ghcupInfo) tool)+              $ _vmTags =<< M.elems (availableToolVersions (_ghcupDownloads ghcupInfo) tool)         pure $ nub $ (add ++) $ fmap tagToString allTags       VLeft _ -> pure  (nub $ ["recommended", "latest", "latest-prerelease"] ++ add) @@ -297,19 +312,20 @@ versionCompleter' criteria tool filter' = listIOCompleter $ do   dirs' <- liftIO getAllDirs   let loggerConfig = LoggerConfig-        { lcPrintDebug   = False+        { lcPrintDebugLvl = Nothing         , consoleOutter  = mempty         , fileOutter     = mempty         , fancyColors    = False         }+  mpFreq <- flip runReaderT loggerConfig . runE $ platformRequest   let settings = defaultSettings { noNetwork = True }-  let leanAppState = LeanAppState-                   settings-                   dirs'-                   defaultKeyBindings-                   loggerConfig-  mpFreq <- flip runReaderT leanAppState . runE $ platformRequest   forFold mpFreq $ \pfreq -> do+    let leanAppState = LeanAppState+                     settings+                     dirs'+                     defaultKeyBindings+                     pfreq+                     loggerConfig     mGhcUpInfo <- flip runReaderT leanAppState . runE $ getDownloadsF pfreq     forFold mGhcUpInfo $ \ghcupInfo -> do       let appState = AppState@@ -320,10 +336,10 @@             pfreq             loggerConfig -          runEnv = flip runReaderT appState+          runEnv = flip runReaderT appState . runE -      installedVersions <- runEnv $ listVersions (Just tool) criteria False False (Nothing, Nothing)-      return $ fmap (T.unpack . prettyVer) . filter filter' . fmap lVer $ installedVersions+      (VRight installedVersions) <- runEnv $ listVersions (Just [tool]) criteria ShowUpdates False False (Nothing, Nothing)+      return $ fmap (T.unpack . prettyVer) . filter filter' . maybe [] (fmap lVer . snd) $ M.lookup tool installedVersions   toolDlCompleter :: Tool -> Completer@@ -363,9 +379,9 @@     | "https://github.com/c" `isPrefixOf` word -> pure ["https://github.com/commercialhaskell/stack/releases/download/"]     | "https://github.com/h" `isPrefixOf` word -> pure ["https://github.com/haskell/haskell-language-server/releases/download/"]     | "https://g" `isPrefixOf` word-    , tool == Stack -> pure ["https://github.com/commercialhaskell/stack/releases/download/"]+    , tool == stack -> pure ["https://github.com/commercialhaskell/stack/releases/download/"]     | "https://g" `isPrefixOf` word-    , tool == HLS -> pure ["https://github.com/haskell/haskell-language-server/releases/download/"]+    , tool == hls -> pure ["https://github.com/haskell/haskell-language-server/releases/download/"]      | "https://d" `isPrefixOf` word -> pure $ filter ("https://downloads.haskell.org/" `isPrefixOf`) $ initUrl tool @@ -378,19 +394,20 @@     | otherwise -> pure []  where   initUrl :: Tool -> [String]-  initUrl GHC   = [ "https://downloads.haskell.org/~ghc/"-                  , "https://downloads.haskell.org/~ghcup/unofficial-bindists/ghc/"-                  ]-  initUrl Cabal = [ "https://downloads.haskell.org/~cabal/"-                  , "https://downloads.haskell.org/~ghcup/unofficial-bindists/cabal/"-                  ]-  initUrl GHCup = [ "https://downloads.haskell.org/~ghcup/" ]-  initUrl HLS   = [ "https://github.com/haskell/haskell-language-server/releases/download/"-                  , "https://downloads.haskell.org/~ghcup/unofficial-bindists/haskell-language-server/"-                  ]-  initUrl Stack = [ "https://github.com/commercialhaskell/stack/releases/download/"-                  , "https://downloads.haskell.org/~ghcup/unofficial-bindists/stack/"-                  ]+  initUrl (Tool "ghc")   = [ "https://downloads.haskell.org/~ghc/"+                           , "https://downloads.haskell.org/~ghcup/unofficial-bindists/ghc/"+                           ]+  initUrl (Tool "cabal") = [ "https://downloads.haskell.org/~cabal/"+                           , "https://downloads.haskell.org/~ghcup/unofficial-bindists/cabal/"+                           ]+  initUrl (Tool "ghcup") = [ "https://downloads.haskell.org/~ghcup/" ]+  initUrl (Tool "hls")   = [ "https://github.com/haskell/haskell-language-server/releases/download/"+                           , "https://downloads.haskell.org/~ghcup/unofficial-bindists/haskell-language-server/"+                           ]+  initUrl (Tool "stack") = [ "https://github.com/commercialhaskell/stack/releases/download/"+                           , "https://downloads.haskell.org/~ghcup/unofficial-bindists/stack/"+                           ]+  initUrl _              = []    completePrefix :: String -- ^ url, e.g.    'https://github.com/haskell/haskell-languag'                  -> String -- ^ match, e.g.  'haskell-language-server'@@ -452,11 +469,10 @@   getGithubAssets owner repo tag = withCurl url 3_000_000 $ \stdout -> do     Just xs <- pure $ decode' @Object stdout     Just (Array assets) <- pure $ KM.lookup (mkval "assets") xs-    as <- fmap V.toList $ forM assets $ \val -> do+    fmap V.toList $ forM assets $ \val -> do       (Object asset) <- pure val       Just (String name) <- pure $ KM.lookup (mkval "name") asset       pure $ T.unpack name-    pure as    where     url = "https://api.github.com/repos/" <> owner <> "/" <> repo <> "/releases/tags/" <> tag @@ -472,33 +488,45 @@                    , HasGHCupInfo env                    , HasDirs env                    , HasPlatformReq env-                   , MonadCatch m                    , HasLog env-                   , MonadThrow m-                   , MonadIO m-                   , MonadFail m+                   , MonadIOish m                    )-                => m [(Tool, GHCTargetVersion)]+                => m [(Tool, TargetVersionRev)] checkForUpdates = do-  GHCupInfo { _ghcupDownloads = dls } <- getGHCupInfo-  lInstalled <- listVersions Nothing [ListInstalled True] False False (Nothing, Nothing)-  let latestInstalled tool = (fmap (\lr -> GHCTargetVersion (lCross lr) (lVer lr)) . lastMay . filter (\lr -> lTool lr == tool)) lInstalled+  dl@GHCupInfo { _ghcupDownloads = dls } <- getGHCupInfo+  pfreq <- getPlatformReq+  (VRight lInstalled') <- runE $ listVersions Nothing [ListInstalled True] ShowUpdates False False (Nothing, Nothing)+  let latestInstalled tool = do+        (_, xs) <- M.lookup tool lInstalled'+        ListResult{..} <- lastMay xs+        pure $ TargetVersion lCross lVer -  ghcup <- forMM (getLatest dls GHCup) $ \(GHCTargetVersion _ l, _) -> do+  ghcup' <- forMM (getLatest dls ghcup) $ \(TargetVersion _ l) -> do     (Right ghcup_ver) <- pure $ version $ prettyPVP ghcUpVer-    if (l > ghcup_ver) then pure $ Just (GHCup, mkTVer l) else pure Nothing+    let tver = mkTVer l+    let rev = maybe 0 (\(_, i, _) -> i) $ getRev dls ghcup tver Nothing+    if l > ghcup_ver then pure $ Just (ghcup, TargetVersionRev tver rev) else pure Nothing -  otherTools <- forM [GHC, Cabal, HLS, Stack] $ \t ->-    forMM (getLatest dls t) $ \(l, _) -> do+  otherTools <- forM (fst <$> allAvailableTools dls) $ \t ->+    forMM (getLatest dls t) $ \l -> do       let mver = latestInstalled t+      let rev = maybe 0 (\(_, i, _) -> i) $ getRev dls t l Nothing       forMM mver $ \ver ->-        if (l > ver) then pure $ Just (t, l) else pure Nothing+        if l > ver then pure $ Just (t, TargetVersionRev l rev) else pure Nothing -  pure $ catMaybes (ghcup:otherTools)+  let revUpdates = mconcat $ M.toList lInstalled' <&> \(tool, (_, lrs)) -> catMaybes $+        lrs <&> \ListResult{..} -> do+          let tver = TargetVersion lCross lVer+          (rev, _) <- either (const Nothing) pure $ getDownloadInfo tool (TargetVersionReq tver Nothing) dl pfreq+          if rev > fst lRev+          then Just (tool, TargetVersionRev tver rev)+          else Nothing++  pure $ nub (catMaybes (ghcup':otherTools) <> revUpdates)  where   forMM a f = fmap join $ forM a f -logGHCPostRm :: (MonadReader env m, HasLog env, MonadIO m) => GHCTargetVersion -> m ()+logGHCPostRm :: (MonadReader env m, HasLog env, MonadIO m) => TargetVersion -> m () logGHCPostRm ghcVer = do   cabalStore <- liftIO $ handleIO (\_ -> if isWindows then pure "C:\\cabal\\store" else pure "~/.cabal/store or ~/.local/state/cabal/store")     getStoreDir
lib-opt/GHCup/OptParse/Compile.hs view
@@ -1,52 +1,55 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE TypeApplications  #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell   #-}-{-# LANGUAGE QuasiQuotes       #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-}  module GHCup.OptParse.Compile where  -import           GHCup-import qualified GHCup.GHC as GHC-import qualified GHCup.HLS as HLS-import           GHCup.Errors-import           GHCup.Types-import           GHCup.Types.Optics-import           GHCup.Utils-import           GHCup.Utils.Parsers (fromVersion, uriParser, ghcVersionTagEither, isolateParser, overWriteVersionParser)-import           GHCup.Prelude.Logger-import           GHCup.Prelude.String.QQ-import           GHCup.OptParse.Common+import GHCup.Command.Set+import GHCup.Errors+import GHCup.Input.Parsers+import GHCup.OptParse.Common+import GHCup.Prelude.Logger+import GHCup.Prelude.String.QQ+import GHCup.Query.DB+import GHCup.Query.GHCupDirs+import GHCup.Query.Metadata+import GHCup.Types+import GHCup.Types.Optics +import qualified GHCup.Command.Compile.GHC as GHC+import qualified GHCup.Command.Compile.HLS as HLS+ #if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )+import Control.Monad.Fail ( MonadFail ) #endif-import           Control.Monad (when, forM_, forM)-import           Control.Concurrent (threadDelay)-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-import           Data.Bifunctor-import           Data.Functor-import           Data.Maybe-import           Data.Versions                  ( Version, prettyVer, version, pvp )-import qualified Data.Versions as V-import           Data.Text                      ( Text )-import           Data.Variant.Excepts-import           Options.Applicative     hiding ( style )-import           Options.Applicative.Pretty.Shim ( text, vsep )-import           Prelude                 hiding ( appendFile )-import           System.Exit+import Control.Concurrent              ( threadDelay )+import Control.Exception.Safe          ( MonadMask, displayException )+import Control.Monad                   ( forM, forM_, when, (<=<) )+import Control.Monad.Reader+import Control.Monad.Trans.Resource+import Data.Bifunctor+import Data.Functor+import Data.Maybe+import Data.Text                       ( Text )+import Data.Variant.Excepts+import Data.Versions                   ( Version, prettyVer, pvp, version )+import Options.Applicative             hiding ( ParseError, style )+import Options.Applicative.Pretty.Shim ( text, vsep )+import Prelude                         hiding ( appendFile )+import System.Exit+import System.FilePath                 ( isPathSeparator )+import Text.PrettyPrint.HughesPJClass  ( prettyShow )+import Text.Read                       ( readEither )+import URI.ByteString                  hiding ( uriParser ) -import           URI.ByteString          hiding ( uriParser )-import qualified Data.Text                     as T-import Control.Exception.Safe (MonadMask, displayException)-import System.FilePath (isPathSeparator)-import Text.Read (readEither)+import qualified Data.Text     as T+import qualified Data.Versions as V   @@ -56,9 +59,10 @@     ----------------  -data CompileCommand = CompileGHC GHCCompileOptions-                    | CompileHLS HLSCompileOptions-                    deriving (Eq, Show)+data CompileCommand+  = CompileGHC GHCCompileOptions+  | CompileHLS HLSCompileOptions+  deriving (Eq, Show)   @@ -68,36 +72,38 @@   data GHCCompileOptions = GHCCompileOptions-  { targetGhc    :: GHC.GHCVer+  { targetGhc :: GHC.GHCVer   , bootstrapGhc :: Either Version FilePath-  , hadrianGhc   :: Maybe (Either Version FilePath)-  , jobs         :: Maybe Int-  , buildConfig  :: Maybe FilePath-  , patches      :: Maybe (Either FilePath [URI])-  , crossTarget  :: Maybe Text-  , addConfArgs  :: [Text]-  , setCompile   :: Bool+  , hadrianGhc :: Maybe (Either Version FilePath)+  , jobs :: Maybe Int+  , buildConfig :: Maybe FilePath+  , patches :: Maybe (Either FilePath [URI])+  , crossTarget :: Maybe Text+  , addConfArgs :: [String]+  , setCompile :: Bool   , overwriteVer :: Maybe [VersionPattern]   , buildFlavour :: Maybe String-  , buildSystem  :: Maybe BuildSystem-  , isolateDir   :: Maybe FilePath-  , installTargets :: T.Text-  } deriving (Eq, Show)+  , buildSystem :: Maybe BuildSystem+  , isolateDir :: Maybe FilePath+  , installTargets :: Maybe [String]+  }+  deriving (Eq, Show)   data HLSCompileOptions = HLSCompileOptions-  { targetHLS    :: HLS.HLSVer-  , jobs         :: Maybe Int-  , setCompile   :: Bool-  , updateCabal  :: Bool+  { targetHLS :: HLS.HLSVer+  , jobs :: Maybe Int+  , setCompile :: Bool+  , updateCabal :: Bool   , overwriteVer :: Maybe [VersionPattern]-  , isolateDir   :: Maybe FilePath+  , isolateDir :: Maybe FilePath   , cabalProject :: Maybe (Either FilePath URI)   , cabalProjectLocal :: Maybe URI-  , patches      :: Maybe (Either FilePath [URI])-  , targetGHCs   :: [ToolVersion]-  , cabalArgs    :: [Text]-  } deriving (Eq, Show)+  , patches :: Maybe (Either FilePath [URI])+  , targetGHCs :: [ToolVersion]+  , cabalArgs :: [Text]+  }+  deriving (Eq, Show)   @@ -174,7 +180,7 @@           )           (short 'v' <> long "version" <> metavar "VERSION" <> help             "The tool version to compile"-            <> (completer $ versionCompleter [] GHC)+            <> completer (versionCompleter [] ghc)           )           ) <|>           (GHC.GitDist <$> (GitBranch <$> option@@ -189,7 +195,7 @@           ))           <|>           (-           GHC.RemoteDist <$> (option+           GHC.RemoteDist <$> option             (eitherReader uriParser)             (long "remote-source-dist" <> metavar "URI" <> help               "URI (https/http/file) to a GHC source distribution"@@ -197,7 +203,6 @@             )           )           )-          )     <*> option           (eitherReader             (\x ->@@ -209,7 +214,7 @@           <> metavar "BOOTSTRAP_GHC"           <> help                "The GHC version (or full path) to bootstrap with (must be installed)"-          <> (completer $ versionCompleter [] GHC)+          <> completer (versionCompleter [] ghc)           )     <*> optional (option           (eitherReader@@ -221,19 +226,19 @@           <> metavar "HADRIAN_GHC"           <> help                "The GHC version (or full path) that will be used to compile hadrian (must be installed)"-          <> (completer $ versionCompleter [] GHC)+          <> completer (versionCompleter [] ghc)           ))     <*> optional           (option             (eitherReader (readEither @Int))             (short 'j' <> long "jobs" <> metavar "JOBS" <> help               "How many jobs to use for make"-              <> (completer $ listCompleter $ fmap show ([1..12] :: [Int]))+              <> completer (listCompleter $ fmap show ([1..12] :: [Int]))             )           )-    <*> (optional+    <*> optional           (-            (fmap Right $ many $ option+            fmap Right (many $ option               (eitherReader uriParser)               (long "patch" <> metavar "PATCH_URI" <> help                 "URI to a patch (https/http/file)"@@ -241,7 +246,7 @@               )             )             <|>-            (fmap Left $ option+            fmap Left (option               str               (short 'p' <> long "patchdir" <> metavar "PATCH_DIR" <> help                 "Absolute path to patch directory (applies all .patch and .diff files in order using -p1. This order is determined by a quilt series file if it exists, or the patches are lexicographically ordered)"@@ -249,7 +254,6 @@               )             )           )-        )     <*> optional           (option             str@@ -271,7 +275,7 @@                                       , text "%H  long commit hash"                                       , text "%g  'git describe' output"                                       ])-            <> (completer $ versionCompleter [] GHC)+            <> completer (versionCompleter [] ghc)             )           )     <*> optional@@ -288,12 +292,12 @@          <|>          ((\b c -> case (b, c) of                           -- --make specified-                          (True, _) -> (Just Make, c)+                          (True, _)       -> (Just Make, c)                           -- only --config specified... assume make                           (False, Just _) -> (Just Make, c)                           -- otherwise fall back to runtime detection of build                           -- system-                          (False, _) -> (Nothing, c)) <$> switch+                          (False, _)      -> (Nothing, c)) <$> switch           (long "make" <> help "Use the make build system instead of hadrian. Tries to detect by default."           )           <*> optional@@ -316,24 +320,24 @@             <> completer (bashCompleter "directory")             )            )-    <*> strOption+    <*> optional (option (eitherReader installTargetParser)            (  long "install-targets"            <> metavar "TARGETS"-           <> help "Space separated list of install targets (default: install)"+           <> help "Overwrite make based install targets"            <> completer (listCompleter ["install", "install_bin", "install_lib", "install_extra", "install_man", "install_docs", "install_data", "update_package_db"])-           <> value "install"            )+           )  hlsCompileOpts :: Parser HLSCompileOptions hlsCompileOpts =   HLSCompileOptions     <$> ((HLS.HackageDist <$> option           (eitherReader-            ((>>= first displayException . V.version . V.prettyPVP) . first (const "Not a valid PVP version") . pvp . T.pack)+            ((first displayException . V.version . V.prettyPVP) <=< first (const "Not a valid PVP version") . pvp . T.pack)           )           (short 'v' <> long "version" <> metavar "VERSION" <> help             "The version to compile (pulled from hackage)"-            <> (completer $ versionCompleter' [] HLS (either (const False) (const True) . V.pvp . V.prettyVer))+            <> completer (versionCompleter' [] hls (either (const False) (const True) . V.pvp . V.prettyVer))           )           )           <|>@@ -347,18 +351,18 @@           ))           ))           <|>-          (HLS.SourceDist <$> (option+          (HLS.SourceDist <$> option             (eitherReader               (first (const "Not a valid version") . version . T.pack)             )           (long "source-dist" <> metavar "VERSION" <> help             "The version to compile (pulled from packaged git sources)"-            <> (completer $ versionCompleter [] HLS)+            <> completer (versionCompleter [] hls)           )-          ))+          )           <|>           (-           HLS.RemoteDist <$> (option+           HLS.RemoteDist <$> option             (eitherReader uriParser)             (long "remote-source-dist" <> metavar "URI" <> help               "URI (https/http/file) to a HLS source distribution"@@ -366,13 +370,12 @@             )           )           )-          )     <*> optional           (option             (eitherReader (readEither @Int))             (short 'j' <> long "jobs" <> metavar "JOBS" <> help               "How many jobs to use for make"-              <> (completer $ listCompleter $ fmap show ([1..12] :: [Int]))+              <> completer (listCompleter $ fmap show ([1..12] :: [Int]))             )           )     <*> fmap (fromMaybe True) (invertableSwitch "set" Nothing True (help "Don't set as active version after install"))@@ -390,16 +393,15 @@                                       , text "%H  long commit hash"                                       , text "%g  'git describe' output"                                       ])-            <> (completer $ versionCompleter [] HLS)+            <> completer (versionCompleter [] hls)             )           )           <|>-          ((\b -> if b then Just [GitDescribe] else Nothing) <$> (switch+          ((\b -> if b then Just [GitDescribe] else Nothing) <$> switch                       (long "git-describe-version"                          <> help "Use the output of 'git describe' (if building from git) as the VERSION component of the installed binary."                          <> internal                       )-                    )           )           )     <*> optional@@ -414,7 +416,7 @@            )     <*> optional           (option-            ((fmap Right $ eitherReader uriParser) <|> (fmap Left str))+            (fmap Right (eitherReader uriParser) <|> fmap Left str)             (long "cabal-project" <> metavar "CABAL_PROJECT" <> help               "If relative filepath, specifies the path to cabal.project inside the unpacked HLS tarball/checkout. Otherwise expects a full URI with https/http/file scheme."               <> completer fileUri@@ -428,9 +430,9 @@               <> completer fileUri             )           )-    <*> (optional+    <*> optional           (-            (fmap Right $ many $ option+            fmap Right (many $ option               (eitherReader uriParser)               (long "patch" <> metavar "PATCH_URI" <> help                 "URI to a patch (https/http/file)"@@ -438,7 +440,7 @@               )             )             <|>-            (fmap Left $ option+            fmap Left (option               str               (short 'p' <> long "patchdir" <> metavar "PATCH_DIR" <> help                 "Absolute path to patch directory (applies all .patch and .diff files in order using -p1)"@@ -446,12 +448,11 @@               )             )           )-        )     <*> some (           option (eitherReader ghcVersionTagEither)             (  long "ghc" <> metavar "GHC_VERSION|TAG" <> help "For which GHC version to compile for (can be specified multiple times)"-            <> completer (tagCompleter GHC [])-            <> completer (versionCompleter [] GHC))+            <> completer (tagCompleter ghc [])+            <> completer (versionCompleter [] ghc))         )     <*> many (argument str (metavar "CABAL_ARGS" <> help "Additional arguments to cabal install, prefix with '-- ' (longopts)")) @@ -488,7 +489,12 @@                   , UninstallFailed                   , MergeFileTreeError                   , URIParseError+                  , FileAlreadyExistsError+                  , ParseError+                  , NoInstallInfo+                  , MalformedInstallInfo                   ]+ type HLSEffects = '[ AlreadyInstalled                   , BuildFailed                   , DigestError@@ -511,32 +517,15 @@                   , UninstallFailed                   , MergeFileTreeError                   , URIParseError+                  , ParseError+                  , NoInstallInfo+                  , MalformedInstallInfo                   ]   -runCompileGHC :: (MonadUnliftIO m, MonadIO m)-              => (ReaderT AppState m (VEither GHCEffects a) -> m (VEither GHCEffects a))-              -> Excepts GHCEffects (ResourceT (ReaderT AppState m)) a-              -> m (VEither GHCEffects a)-runCompileGHC runAppState =-        runAppState-        . runResourceT-        . runE-          @GHCEffects -runCompileHLS :: (MonadUnliftIO m, MonadIO m)-              => (ReaderT AppState m (VEither HLSEffects a) -> m (VEither HLSEffects a))-              -> Excepts HLSEffects (ResourceT (ReaderT AppState m)) a-              -> m (VEither HLSEffects a)-runCompileHLS runAppState =-        runAppState-        . runResourceT-        . runE-          @HLSEffects --     ------------------     --[ Entrypoint ]--     ------------------@@ -551,51 +540,62 @@       => CompileCommand       -> Settings       -> Dirs-      -> (forall eff a . ReaderT AppState m (VEither eff a) -> m (VEither eff a))-      -> (ReaderT LeanAppState m () -> m ())+      -> (IO (AppState, IO ()), LeanAppState)       -> m ExitCode-compile compileCommand settings Dirs{..} runAppState runLogger = do+compile compileCommand settings Dirs{..} (getAppState', leanAppstate) = do+  (s', updateCheckAction) <- liftIO getAppState'+  liftIO updateCheckAction   case compileCommand of     (CompileHLS HLSCompileOptions { .. }) -> do-      runCompileHLS runAppState (do+      runCompileHLS s' (do         case targetHLS of           HLS.SourceDist targetVer -> do             GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-            let vi = getVersionInfo (mkTVer targetVer) HLS dls-            forM_ (_viPreInstall =<< vi) $ \msg -> do+            let vm = getVersionMetadata (mkTVer targetVer) hls dls+            forM_ (_vmPreInstall =<< vm) $ \msg -> do               lift $ logWarn msg               lift $ logWarn                 "...waiting for 5 seconds, you can still abort..."               liftIO $ threadDelay 5000000 -- give the user a sec to intervene-            forM_ (_viPreCompile =<< vi) $ \msg -> do+            forM_ (_vmPreCompile =<< vm) $ \msg -> do               lift $ logWarn msg               lift $ logWarn                 "...waiting for 5 seconds, you can still abort..."               liftIO $ threadDelay 5000000 -- for compilation, give the user a sec to intervene           _ -> pure ()-        ghcs <- liftE $ forM targetGHCs (\ghc -> fmap (_tvVersion . fst) . fromVersion (Just ghc) guessMode $ GHC)-        targetVer <- liftE $ compileHLS+        ghcs' <- liftE $ forM targetGHCs (\ghc' -> resolveVersion (Just ghc') guessMode ghc)+        ghcs <- forM ghcs' $ \TargetVersionReq{..} -> do+          when (isJust $ _tvTarget _tvqTargetVer) $ fail "Cannot compile HLS for a cross GHC"+          pure (_tvVersion _tvqTargetVer)++        let instDir = maybe GHCupInternal IsolateDir isolateDir+        targetVer <- liftE $ HLS.compileHLS                     targetHLS                     ghcs                     jobs                     overwriteVer-                    (maybe GHCupInternal IsolateDir isolateDir)+                    instDir                     cabalProject                     cabalProjectLocal                     updateCabal                     patches                     cabalArgs         GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-        let vi = getVersionInfo (mkTVer targetVer) HLS dls-        when setCompile $ void $ liftE $-          setHLS targetVer SetHLSOnly Nothing-        pure (vi, targetVer)+        let vm = getVersionMetadata (mkTVer targetVer) hls dls+        -- TODO: also set if it's already set+        case instDir of+          GHCupInternal -> do+            set <- liftE $ isSet hls (mkTVer targetVer)+            when (setCompile || isJust set) $ void $ liftE $+              setToolVersion hls (mkTVer targetVer)+          IsolateDir _ -> pure ()+        pure (vm, targetVer)         )         >>= \case-              VRight (vi, tv) -> do+              VRight (vm, tv) -> do                 runLogger $ logInfo                   "HLS successfully compiled and installed"-                forM_ (_viPostInstall =<< vi) $ \msg ->+                forM_ (_vmPostInstall =<< vm) $ \msg ->                   runLogger $ logInfo msg                 liftIO $ putStr (T.unpack $ prettyVer tv)                 pure ExitSuccess@@ -611,23 +611,24 @@                 runLogger $ logError $ T.pack $ prettyHFError e                 pure $ ExitFailure 9     (CompileGHC GHCCompileOptions {..}) ->-      runCompileGHC runAppState (do+      runCompileGHC s' (do         case targetGhc of           GHC.SourceDist targetVer -> do             GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-            let vi = getVersionInfo (mkTVer targetVer) GHC dls-            forM_ (_viPreInstall =<< vi) $ \msg -> do+            let vm = getVersionMetadata (mkTVer targetVer) ghc dls+            forM_ (_vmPreInstall =<< vm) $ \msg -> do               lift $ logWarn msg               lift $ logWarn                 "...waiting for 5 seconds, you can still abort..."               liftIO $ threadDelay 5000000 -- give the user a sec to intervene-            forM_ (_viPreCompile =<< vi) $ \msg -> do+            forM_ (_vmPreCompile =<< vm) $ \msg -> do               lift $ logWarn msg               lift $ logWarn                 "...waiting for 5 seconds, you can still abort..."               liftIO $ threadDelay 5000000 -- for compilation, give the user a sec to intervene           _ -> pure ()-        targetVer <- liftE $ compileGHC+        let instDir = maybe GHCupInternal IsolateDir isolateDir+        targetVer <- liftE $ GHC.compileGHC                     targetGhc                     crossTarget                     overwriteVer@@ -639,25 +640,29 @@                     addConfArgs                     buildFlavour                     buildSystem-                    (maybe GHCupInternal IsolateDir isolateDir)+                    instDir                     installTargets         GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-        let vi = getVersionInfo targetVer GHC dls-        when setCompile $ void $ liftE $-          setGHC targetVer SetGHCOnly Nothing-        pure (vi, targetVer)+        let vm = getVersionMetadata targetVer ghc dls+        case instDir of+          GHCupInternal -> do+            set <- liftE $ isSet ghc targetVer+            when (setCompile || isJust set) $ void $ liftE $+              setToolVersion ghc targetVer+          IsolateDir _ -> pure ()+        pure (vm, targetVer)         )         >>= \case-              VRight (vi, tv) -> do+              VRight (vm, tv) -> do                 runLogger $ logInfo                   "GHC successfully compiled and installed"-                forM_ (_viPostInstall =<< vi) $ \msg ->+                forM_ (_vmPostInstall =<< vm) $ \msg ->                   runLogger $ logInfo msg                 liftIO $ putStr (T.unpack $ tVerToText tv)                 pure ExitSuccess               VLeft (V (AlreadyInstalled _ v)) -> do                 runLogger $ logWarn $-                  "GHC ver " <> prettyVer v <> " already installed, remove it first to reinstall"+                  "GHC ver " <> T.pack (prettyShow v) <> " already installed, remove it first to reinstall"                 pure ExitSuccess               VLeft (V (DirNotEmpty fp)) -> do                 runLogger $ logError $@@ -675,5 +680,15 @@                 runLogger $ logError $ T.pack $ prettyHFError e                 pure $ ExitFailure 9  where+  runLogger = flip runReaderT leanAppstate   guessMode = if guessVersion settings then GLaxWithInstalled else GStrict-+  runCompileGHC appstate' =+    flip runReaderT appstate'+                  . runResourceT+                  . runE+                    @GHCEffects+  runCompileHLS appstate' =+    flip runReaderT appstate'+                  . runResourceT+                  . runE+                    @HLSEffects
lib-opt/GHCup/OptParse/Config.hs view
@@ -1,45 +1,45 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE TypeApplications  #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE TemplateHaskell   #-}-{-# LANGUAGE QuasiQuotes       #-}-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-}  module GHCup.OptParse.Config where  -import           GHCup.Errors-import           GHCup.Types-import           GHCup.Utils-import           GHCup.Utils.Parsers (parseNewUrlSource)-import           GHCup.Prelude-import           GHCup.Prelude.Logger-import           GHCup.Prelude.String.QQ-import           GHCup.OptParse.Common-import           GHCup.Version+import GHCup.Errors+import GHCup.Hardcoded.URLs+import GHCup.Input.Parsers     ( parseNewUrlSource )+import GHCup.OptParse.Common+import GHCup.OptParse.Reset    ( resetUserConfig, toUserSettingsKey )+import GHCup.Prelude+import GHCup.Prelude.String.QQ+import GHCup.Query.GHCupDirs+import GHCup.Types  #if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )+import Control.Monad.Fail ( MonadFail ) #endif-import           Control.Monad (when)-import           Control.Exception              ( displayException )-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-import           Data.Functor-import           Data.Maybe-import           Data.Variant.Excepts-import           Options.Applicative     hiding ( style, ParseError )-import           Options.Applicative.Pretty.Shim ( text )-import           Prelude                 hiding ( appendFile )-import           System.Exit+import Control.Exception               ( displayException )+import Control.Exception.Safe          ( MonadMask )+import Control.Monad                   ( when )+import Control.Monad.Reader+import Control.Monad.Trans.Resource+import Data.Foldable                   ( foldl' )+import Data.Functor+import Data.Maybe+import Data.Variant.Excepts+import Options.Applicative             hiding ( ParseError, style )+import Options.Applicative.Pretty.Shim ( text )+import Prelude                         hiding ( appendFile )+import System.Exit -import qualified Data.Text                     as T-import qualified Data.ByteString.UTF8          as UTF8-import qualified Data.Yaml.Aeson               as Y-import Control.Exception.Safe (MonadMask)+import qualified Data.ByteString.UTF8 as UTF8+import qualified Data.Text            as T+import qualified Data.Yaml.Aeson      as Y   @@ -52,10 +52,15 @@ data ConfigCommand   = ShowConfig   | SetConfig String (Maybe String)+  | ResetConfig ResetCommand   | InitConfig   | AddReleaseChannel Bool NewURLSource   deriving (Eq, Show) +data ResetCommand+  = ResetKeys [String]+  | ResetAll+  deriving (Eq, Show)       ---------------@@ -67,6 +72,7 @@ configP = subparser       (  command "init" initP       <> command "set"  setP -- [set] KEY VALUE at help lhs+      <> command "reset" resetP       <> command "show" showP       <> command "add-release-channel" addP       )@@ -74,15 +80,24 @@  where   initP = info (pure InitConfig) (progDesc "Write default config to ~/.ghcup/config.yaml")   showP = info (pure ShowConfig) (progDesc "Show current config (default)")-  setP  = info argsP (progDesc "Set config KEY to VALUE (or specify as single json value)" <> footerDoc (Just $ text configSetFooter))-  argsP = SetConfig <$> argument str (metavar "<JSON_VALUE | YAML_KEY>") <*> optional (argument str (metavar "YAML_VALUE"))+  setP  = info setArgsP (progDesc "Set config KEY to VALUE (or specify as single json value)" <> footerDoc (Just $ text configSetFooter))+  setArgsP = SetConfig <$> argument str (metavar "<JSON_VALUE | YAML_KEY>") <*> optional (argument str (metavar "YAML_VALUE"))+  resetP = info resetArgsP+    (progDesc "Reset the whole config or just specific keys" <> footerDoc (Just $ text configResetFooter))+  resetArgsP = ResetConfig <$> subparser+       ( command "all"+         (info (pure ResetAll) (progDesc "Reset the whole config"))+      <> command "keys"+         (info resetKeysP (progDesc "Reset specific keys of the config"))+       )+  resetKeysP = ResetKeys <$> some (strArgument+    (  metavar "YAML_KEY"+    <> help "Specify key(s)" ))   addP  = info (AddReleaseChannel <$> switch (long "force" <> help "Delete existing entry (if any) and append instead of failing")                 <*> argument (eitherReader parseNewUrlSource) (metavar "<URL_SOURCE|cross|prereleases|vanilla>" <> completer urlSourceCompleter))     (progDesc "Add a release channel, e.g. from a URI or using alias")  --     --------------     --[ Footer ]--     --------------@@ -100,6 +115,9 @@   # set <key> <value> configuration pair   ghcup config set <key> <value> +  # reset config key(s)+  ghcup config reset keys <key> <key> ...+   # add a release channel   ghcup config add-release-channel prereleases|] @@ -120,8 +138,18 @@   # set mirror for ghcup metadata   ghcup config set '{url-source: { OwnSource: "<url>"}}'|] +configResetFooter :: String+configResetFooter = [s|Examples:+  # reset the whole config+  ghcup config reset all +  # reset one key (cache)+  ghcup config reset keys cache +  # reset some keys (cache, url-source and downloader)+  ghcup config reset keys cache url-source downloader|]++     -----------------     --[ Utilities ]--     -----------------@@ -148,7 +176,8 @@        defGHCconfOptions' = uDefGHCConfOptions usl <|> uDefGHCConfOptions usr        pagerConfig' = uPager usl <|> uPager usr        guessVersion' = uGuessVersion usl <|> uGuessVersion usr-   in UserSettings cache' metaCache' metaMode' noVerify' verbose' keepDirs' downloader' (updateKeyBindings (uKeyBindings usl) (uKeyBindings usr)) urlSource' noNetwork' gpgSetting' platformOverride' mirrors' defGHCconfOptions' pagerConfig' guessVersion'+       buildWrapper' = uBuildWrapper usl <|> uBuildWrapper usr+   in UserSettings cache' metaCache' metaMode' noVerify' verbose' keepDirs' downloader' (updateKeyBindings (uKeyBindings usl) (uKeyBindings usr)) urlSource' noNetwork' gpgSetting' platformOverride' mirrors' defGHCconfOptions' pagerConfig' guessVersion' buildWrapper'  where   updateKeyBindings :: Maybe UserKeyBindings -> Maybe UserKeyBindings -> Maybe UserKeyBindings   updateKeyBindings Nothing Nothing = Nothing@@ -159,6 +188,9 @@            kUp = kUp kbl <|> kUp kbr          , kDown = kDown kbl <|> kDown kbr          , kQuit = kQuit kbl <|> kQuit kbr+         , kLeft = kLeft kbl <|> kLeft kbr+         , kRight = kRight kbl <|> kRight kbr+         , kTab = kTab kbl <|> kTab kbr          , kInstall = kInstall kbl <|> kInstall kbr          , kUninstall = kUninstall kbl <|> kUninstall kbr          , kSet = kSet kbl <|> kSet kbr@@ -172,9 +204,10 @@     --[ Entrypoint ]--     ------------------ -data Duplicate = Duplicate     -- ^ there is a duplicate somewhere in the middle-               | NoDuplicate   -- ^ there is no duplicate-               | DuplicateLast -- ^ there's a duplicate, but it's the last element+data Duplicate+  = Duplicate -- ^ there is a duplicate somewhere in the middle+  | NoDuplicate -- ^ there is no duplicate+  | DuplicateLast   config :: forall m. ( Monad m@@ -186,9 +219,9 @@      -> Settings      -> UserSettings      -> KeyBindings-     -> (ReaderT LeanAppState m () -> m ())+     -> (IO (AppState, IO ()), LeanAppState)      -> m ExitCode-config configCommand settings userConf keybindings runLogger = case configCommand of+config configCommand settings userConf keybindings (_getAppState', leanAppstate) = case configCommand of   InitConfig -> do     path <- getConfigFilePath     liftIO $ writeFile path $ formatConfig $ fromSettings settings (Just keybindings)@@ -224,6 +257,29 @@       VLeft e -> do         runLogger (logError $ T.pack $ prettyHFError e)         pure $ ExitFailure 65+  (ResetConfig resetCommand) -> do+    r <- runE @'[ParseError] $ do+      case resetCommand of+        ResetAll -> do+          lift $ doReset defaultUserSettings+          pure ()+        ResetKeys stringKeys -> do+          lift $ runLogger $ logDebug $ "Raw keys: " <> T.pack (show stringKeys)+          let eKeys = traverse toUserSettingsKey stringKeys+          lift $ runLogger $ logDebug $ "Handled keys: " <> T.pack (show eKeys)+          case eKeys of+            Left invalidString -> do+              throwE $ ParseError $ "Key <<" <> invalidString <> ">> is invalid"+            Right keys -> do+              lift $ runLogger $ logDebug $ "userConf: " <> T.pack (show userConf)+              let newUserConf = foldl' (\conf key -> resetUserConfig conf key ) userConf keys+              lift $ doReset newUserConf+              pure ()+    case r of+      VRight _ -> pure ExitSuccess+      VLeft e -> do+        runLogger (logError $ T.pack $ prettyHFError e)+        pure $ ExitFailure 65    AddReleaseChannel force new -> do     r <- runE @'[DuplicateReleaseChannel] $ do@@ -242,6 +298,8 @@         pure $ ExitFailure 15   where+  runLogger = flip runReaderT leanAppstate+   checkDuplicate :: Eq a => [a] -> a -> Duplicate   checkDuplicate xs a     | last xs == a = DuplicateLast@@ -250,14 +308,21 @@    aliasToURI :: NewURLSource -> NewURLSource   aliasToURI (NewChannelAlias a) = NewURI (channelURL a)-  aliasToURI v = v+  aliasToURI v                   = v    doConfig :: MonadIO m => UserSettings -> m ()   doConfig usersettings = do     let settings' = updateSettings usersettings userConf     path <- liftIO getConfigFilePath-    liftIO $ writeFile path $ formatConfig $ settings'+    liftIO $ writeFile path $ formatConfig settings'     runLogger $ logDebug $ T.pack $ show settings'+    pure ()++  doReset :: MonadIO m => UserSettings -> m ()+  doReset resetUserSettings = do+    path <- liftIO getConfigFilePath+    liftIO $ writeFile path $ formatConfig resetUserSettings+    runLogger $ logDebug $ "reset to config: " <> T.pack (show resetUserSettings)     pure ()    decodeSettings = lE' (JSONDecodeError . displayException) . Y.decodeEither' . UTF8.fromString
− lib-opt/GHCup/OptParse/DInfo.hs
@@ -1,141 +0,0 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE TypeApplications  #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell   #-}-{-# LANGUAGE QuasiQuotes       #-}-{-# LANGUAGE DuplicateRecordFields #-}-{-# LANGUAGE RankNTypes #-}--module GHCup.OptParse.DInfo where-----import           GHCup-import           GHCup.Errors-import           GHCup.Version-import           GHCup.Types-import           GHCup.Utils.Dirs-import           GHCup.Prelude-import           GHCup.Prelude.Logger-import           GHCup.Prelude.Process--#if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )-#endif-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-import           Data.Functor-import           Data.Maybe-import           Data.List                      ( intercalate )-import           Data.Variant.Excepts-import           Options.Applicative     hiding ( style )-import           Prelude                 hiding ( appendFile )-import           System.Exit-import           System.FilePath-import           Text.PrettyPrint.HughesPJClass ( prettyShow )-import           URI.ByteString (serializeURIRef')--import qualified Data.Text                     as T-import Control.Exception.Safe (MonadMask)-import Language.Haskell.TH----    ------------------    --[ Utilities ]---    --------------------describe_result :: String-describe_result = $( LitE . StringL <$>-                     runIO (do-                             CapturedProcess{..} <-  do-                              dirs <- liftIO getAllDirs-                              let settings = AppState (defaultSettings { noNetwork = True })-                                               dirs-                                               defaultKeyBindings-                              flip runReaderT settings $ executeOut "git" ["describe"] Nothing-                             case _exitCode of-                               ExitSuccess   -> pure . T.unpack . decUTF8Safe' $ _stdOut-                               ExitFailure _ -> pure numericVer-                     )-                   )---prettyDebugInfo :: DebugInfo -> String-prettyDebugInfo DebugInfo { diDirs = Dirs { .. }, ..} =-  "===== Main ======"                              <> "\n"  <>-  "Architecture:  "   <> prettyShow diArch         <> "\n"  <>-  "Platform:      "   <> prettyShow diPlatform     <> "\n"  <>-  "GHCup Version: "   <> describe_result           <> "\n"  <>-  "===== Directories ======"                       <> "\n"  <>-  "base:    " <> fromGHCupPath baseDir             <> "\n"  <>-  "bin:     " <> binDir                            <> "\n"  <>-  "GHCs:    " <> (fromGHCupPath baseDir </> "ghc") <> "\n"  <>-  "cache:   " <> fromGHCupPath cacheDir            <> "\n"  <>-  "logs:    " <> fromGHCupPath logsDir             <> "\n"  <>-  "config:  " <> fromGHCupPath confDir             <> "\n"  <>-  "db:      " <> fromGHCupPath dbDir               <> "\n"  <>-  whenWin ("recycle: " <> fromGHCupPath recycleDir <> "\n") <>-  "temp:    " <> fromGHCupPath tmpDir              <> "\n"  <>-  whenWin ("msys2:   " <> msys2Dir                 <> "\n") <>-  "\n===== Metadata ======\n" <>-  intercalate "\n" ((\(c, u) -> pad (c <> ":") <> " " <> u) <$> channels)- where-  pad xs-    | xl < maxLength = xs <> replicate (maxLength - xl) ' '-    | otherwise = xs-   where-    xl = length xs-  channels = (\(c, u) -> (T.unpack . channelAliasText $ c, T.unpack . decUTF8Safe . serializeURIRef'$ u)) <$> diChannels-  maxLength = (+1) . maximum . fmap (length . fst) $ channels-  whenWin x = if isWindows then x else mempty-----    ----------------------------    --[ Effect interpreters ]---    ------------------------------type DInfoEffects = '[ NoCompatiblePlatform , NoCompatibleArch , DistroNotFound ]--runDebugInfo :: (ReaderT env m (VEither DInfoEffects a) -> m (VEither DInfoEffects a))-             -> Excepts DInfoEffects (ReaderT env m) a-             -> m (VEither DInfoEffects a)-runDebugInfo runAppState =-        runAppState-        . runE-          @DInfoEffects----    -------------------    --[ Entrypoint ]---    ----------------------dinfo :: ( Monad m-         , MonadMask m-         , MonadUnliftIO m-         , MonadFail m-         , Alternative m-         )-      => (ReaderT AppState m (VEither DInfoEffects DebugInfo)-          -> m (VEither DInfoEffects DebugInfo))-      -> (ReaderT LeanAppState m () -> m ())-      -> m ExitCode-dinfo runAppState runLogger = do-  runDebugInfo runAppState (liftE getDebugInfo)-    >>= \case-          VRight di -> do-            liftIO $ putStrLn $ prettyDebugInfo di-            pure ExitSuccess-          VLeft e -> do-            runLogger $ logError $ T.pack $ prettyHFError e-            pure $ ExitFailure 8
+ lib-opt/GHCup/OptParse/DebugInfo.hs view
@@ -0,0 +1,142 @@+{-# LANGUAGE CPP               #-}+{-# LANGUAGE DataKinds         #-}+{-# LANGUAGE TypeApplications  #-}+{-# LANGUAGE FlexibleContexts  #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell   #-}+{-# LANGUAGE QuasiQuotes       #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE RankNTypes #-}++module GHCup.OptParse.DebugInfo where+++++import           GHCup.Command.DebugInfo+import           GHCup.Errors+import           GHCup.Hardcoded.Version+import           GHCup.Types+import           GHCup.Query.GHCupDirs+import           GHCup.Prelude+import           GHCup.Prelude.Process++#if !MIN_VERSION_base(4,13,0)+import           Control.Monad.Fail             ( MonadFail )+#endif+import           Control.Monad.Reader+import           Control.Monad.Trans.Resource+import           Data.Functor+import           Data.Maybe+import           Data.List                      ( intercalate )+import           Data.Variant.Excepts+import           Options.Applicative     hiding ( style )+import           Prelude                 hiding ( appendFile )+import           System.Exit+import           System.FilePath+import           Text.PrettyPrint.HughesPJClass ( prettyShow )+import           URI.ByteString (serializeURIRef')++import qualified Data.Text                     as T+import Control.Exception.Safe (MonadMask)+import Language.Haskell.TH+import Data.Bifunctor (bimap)++++    -----------------+    --[ Utilities ]--+    -----------------+++describe_result :: String+describe_result = $( LitE . StringL <$>+                     runIO (do+                             CapturedProcess{..} <-  do+                              dirs <- liftIO getAllDirs+                              let settings = AppState (defaultSettings { noNetwork = True })+                                               dirs+                                               defaultKeyBindings+                              flip runReaderT settings $ executeOut "git" ["describe"] Nothing+                             case _exitCode of+                               ExitSuccess   -> pure . T.unpack . decUTF8Safe' $ _stdOut+                               ExitFailure _ -> pure numericVer+                     )+                   )+++prettyDebugInfo :: DebugInfo -> String+prettyDebugInfo DebugInfo { diDirs = Dirs { .. }, ..} =+  "===== Main ======"                              <> "\n"  <>+  "Architecture:  "   <> prettyShow diArch         <> "\n"  <>+  "Platform:      "   <> prettyShow diPlatform     <> "\n"  <>+  "GHCup Version: "   <> describe_result           <> "\n"  <>+  "===== Directories ======"                       <> "\n"  <>+  "base:    " <> fromGHCupPath baseDir             <> "\n"  <>+  "bin:     " <> binDir                            <> "\n"  <>+  "GHCs:    " <> (fromGHCupPath baseDir </> "ghc") <> "\n"  <>+  "cache:   " <> fromGHCupPath cacheDir            <> "\n"  <>+  "logs:    " <> fromGHCupPath logsDir             <> "\n"  <>+  "config:  " <> fromGHCupPath confDir             <> "\n"  <>+  "db:      " <> fromGHCupPath dbDir               <> "\n"  <>+  whenWin ("recycle: " <> fromGHCupPath recycleDir <> "\n") <>+  "temp:    " <> fromGHCupPath tmpDir              <> "\n"  <>+  whenWin ("msys2:   " <> msys2Dir                 <> "\n") <>+  "\n===== Metadata ======\n" <>+  intercalate "\n" ((\(c, u) -> pad (c <> ":") <> " " <> u) <$> channels)+ where+  pad xs+    | xl < maxLength = xs <> replicate (maxLength - xl) ' '+    | otherwise = xs+   where+    xl = length xs+  channels = bimap (T.unpack . channelAliasText) (T.unpack . decUTF8Safe . serializeURIRef') <$> diChannels+  maxLength = (+1) . maximum . fmap (length . fst) $ channels+  whenWin x = if isWindows then x else mempty+++++    ---------------------------+    --[ Effect interpreters ]--+    ---------------------------+++type DInfoEffects = '[ NoCompatiblePlatform , NoCompatibleArch , DistroNotFound ]++++    ------------------+    --[ Entrypoint ]--+    ------------------++++dinfo :: ( Monad m+         , MonadMask m+         , MonadUnliftIO m+         , MonadFail m+         , Alternative m+         )+      => (IO (AppState, IO ()), LeanAppState)+      -> m ExitCode+dinfo (getAppState', leanAppstate) = do+  run (liftE getDebugInfo)+    >>= \case+          (VRight di, up) -> do+            liftIO $ putStrLn $ prettyDebugInfo di+            liftIO up+            pure ExitSuccess+          (VLeft e, _) -> do+            runLogger $ logError $ T.pack $ prettyHFError e+            pure $ ExitFailure 8+ where+  runLogger = flip runReaderT leanAppstate+  run action' = do+    (appstate', up) <- liftIO getAppState'+    r <- flip runReaderT appstate'+                  . runResourceT+                  . runE+                    @DInfoEffects+                  $ action'+    pure (r, up)
lib-opt/GHCup/OptParse/GC.hs view
@@ -3,7 +3,6 @@ {-# LANGUAGE TypeApplications  #-} {-# LANGUAGE FlexibleContexts  #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell   #-} {-# LANGUAGE QuasiQuotes       #-} {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE RankNTypes #-}@@ -11,7 +10,7 @@ module GHCup.OptParse.GC where  -import           GHCup+import           GHCup.Command.GC import           GHCup.Errors import           GHCup.Types import           GHCup.Prelude.Logger@@ -25,7 +24,7 @@ import           Control.Monad.Trans.Resource import           Data.Functor import           Data.Variant.Excepts-import           Options.Applicative     hiding ( style )+import           Options.Applicative     hiding ( style, ParseError ) import           Prelude                 hiding ( appendFile ) import           System.Exit @@ -102,21 +101,11 @@     ---------------------------  -type GCEffects = '[ NotInstalled, UninstallFailed ]+type GCEffects = '[ NotInstalled, UninstallFailed, ParseError, MalformedInstallInfo ]  -runGC :: MonadUnliftIO m-      => (ReaderT AppState m (VEither GCEffects a) -> m (VEither GCEffects a))-      -> Excepts GCEffects (ResourceT (ReaderT AppState m)) a-      -> m (VEither GCEffects a)-runGC runAppState =-  runAppState-    . runResourceT-    . runE-      @GCEffects  -     ------------------     --[ Entrypoint ]--     ------------------@@ -129,10 +118,9 @@       , MonadFail m       )    => GCOptions-   -> (forall a. ReaderT AppState m (VEither GCEffects a) -> m (VEither GCEffects a))-   -> (ReaderT LeanAppState m () -> m ())+   -> (IO (AppState, IO ()), LeanAppState)    -> m ExitCode-gc GCOptions{..} runAppState runLogger = runGC runAppState (do+gc GCOptions{..} (getAppState', leanAppstate) = run (do   when gcOldGHC (liftE rmOldGHC)   lift $ when gcProfilingLibs rmProfilingLibs   lift $ when gcShareDir rmShareDir@@ -141,8 +129,19 @@   lift $ when gcTmp rmTmp   liftE $ when gcUnset rmUnsetTools    ) >>= \case-            VRight _ -> do-                  pure ExitSuccess-            VLeft e -> do+            (VRight _, up) -> do+              liftIO up+              pure ExitSuccess+            (VLeft e, _) -> do               runLogger $ logError $ T.pack $ prettyHFError e               pure $ ExitFailure 27+ where+  run action' = do+    (appstate', up) <- liftIO getAppState'+    r <- flip runReaderT appstate'+                  . runResourceT+                  . runE+                    @GCEffects+                  $ action'+    pure (r, up)+  runLogger = flip runReaderT leanAppstate
+ lib-opt/GHCup/OptParse/Generate.hs view
@@ -0,0 +1,225 @@+{-# LANGUAGE CPP               #-}+{-# LANGUAGE DataKinds         #-}+{-# LANGUAGE FlexibleContexts  #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE RankNTypes #-}++module GHCup.OptParse.Generate where+++#if defined(DHALL)+import           GHCup.Errors+import           GHCup.Types+import           GHCup.Input.Parsers+import           GHCup.OptParse.Common+import           GHCup.Types.Dhall ()+import           GHCup.Prelude.Logger+import GHCup.Types.Optics+import GHCup.Download+import GHCup.Prelude (decUTF8Safe)++import           Control.Monad.Reader+import           Data.Functor+import           Data.Variant.Excepts+import           Options.Applicative     hiding ( style, ParseError )+import           Prelude                 hiding ( appendFile )+import           System.Exit+import Dhall.Marshal.Encode ()++import qualified Dhall.Core as Dhall+import qualified Dhall.Binary as Dhall+import qualified Data.Either.Validation as Validation+import qualified Dhall hiding (Text)++import qualified Data.Text                     as T+import qualified Data.Text.IO                     as T+import qualified Data.Yaml as YAML+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as BSL+import qualified Data.Void as V++++++    ---------------+    --[ Options ]--+    ---------------++data GenerateCommand = GenerateDhallSchema   GenOutput+                     | GenerateDhallFromYaml ToDhallOptions+                     | GenerateYamlFromDhall GenInput GenOutput+++data ToDhallOptions = ToDhallOptions {+    genInput  :: GenInput+  , genOutput :: GenOutput+  , genBinary :: Bool+  }++data GenOutput = GenOutputFile FilePath+               | GenStdOut+++data GenInput = GenInputURL [NewURLSource]+              | GenStdIn+++    ---------------+    --[ Parsers ]--+    ---------------++generateP :: Parser GenerateCommand+generateP =+  subparser+      (  command+          "dhall-schema"+          (GenerateDhallSchema <$> info (genOutputP <**> helper) (progDesc "Generate Dhall schema from the GHCup types"))+      <> command+          "metadata-to-dhall"+          (GenerateDhallFromYaml+              <$> info (toDhallOptions <**> helper)+            (progDesc "Convert the input metadata to binary Dhall")+          )+      <> command+          "metadata-to-yaml"+          ((\(in', out) -> GenerateYamlFromDhall in' out)+              <$> info ((,) <$> genInputP <*> genOutputP <**> helper)+            (progDesc "Convert the input metadata to expanded YAML")+          )+      )++toDhallOptions :: Parser ToDhallOptions+toDhallOptions =+  ToDhallOptions+    <$> genInputP+    <*> genOutputP+    <*> (+      switch+          (short 'b' <> long "binary" <> help "Convert to Dhall binary format")+    )++genInputP :: Parser GenInput+genInputP =+  maybe GenStdIn GenInputURL <$>+    optional parseUrlSourceP++genOutputP :: Parser GenOutput+genOutputP =+  maybe GenStdOut GenOutputFile <$>+    optional+      (option+       (eitherReader filePathParser)+       (  short 'o'+       <> long "output-file"+       <> metavar "FILEPATH"+       <> help "Write the output to the specified file instead of stdout"+       <> completer (bashCompleter "file")+       )+      )++++    ---------------------------+    --[ Effect interpreters ]--+    ---------------------------+++type GenerateEffects = '[DigestError, ContentLengthError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError, StackPlatformDetectError, UnsupportedMetadataFormat, ParseError]+++++    ------------------+    --[ Entrypoint ]--+    ------------------++++generate ::+  ( MonadIOish m+  )+   => GenerateCommand+   -> (IO (AppState, IO ()), LeanAppState)+   -> m ExitCode+generate gen (_getAppState', leanAppstate) = runLean (do+  pfreq <- lift getPlatformReq+  case gen of+    GenerateDhallSchema genOutput -> do+       withValidation (Dhall.expected (Dhall.auto @GHCupInfo)) $ \(Dhall.pretty -> result) -> do+         toOutputT genOutput result+         pure ()+    GenerateDhallFromYaml (ToDhallOptions genInput genOutput b) -> do+      r <- getInput genInput pfreq+      let dhallExpr = Dhall.denote $ (Dhall.embed @GHCupInfo Dhall.inject) r+      if b+      then toOutputBSL genOutput $ Dhall.encodeExpression dhallExpr+      else toOutputT genOutput $ Dhall.pretty dhallExpr+      pure ()+    GenerateYamlFromDhall genInput genOutput -> do+      r <- getInput genInput pfreq+      toOutputBS genOutput $ YAML.encode r+   ) >>= \case+            VRight _ -> do+              pure ExitSuccess+            VLeft e -> do+              runLogger $ logError $ T.pack $ prettyHFError e+              pure $ ExitFailure 27+ where+  getInput ::+    ( MonadReader env m+    , HasSettings env+    , HasDirs env+    , HasLog env+    , MonadIOish m+    )+    => GenInput+    -> PlatformRequest+    -> Excepts GenerateEffects m GHCupInfo+  getInput genInput pfreq =+    case genInput of+      GenInputURL xs -> do+        ghcupInfo <- liftE $ getDownloadsF' pfreq xs+        pure ghcupInfo+      GenStdIn -> do+        input <- liftIO BS.getContents+        liftIO $ asum [yaml input, dhallB input, dhall input]+   where+    yaml :: BS.ByteString -> IO GHCupInfo+    yaml input = either (fail . show) pure $ YAML.decodeEither' input++    dhallB :: BS.ByteString -> IO GHCupInfo+    dhallB input = do+      expr <- either (fail . show) pure $ Dhall.decodeExpression @V.Void @V.Void (BSL.fromStrict input)+      Dhall.rawInput Dhall.auto expr++    dhall :: BS.ByteString -> IO GHCupInfo+    dhall (decUTF8Safe -> input) = liftIO $ Dhall.input Dhall.auto input++  withValidation val action' =+    case val of+      Validation.Success r -> action' r+      Validation.Failure errors -> do+        throwE $ ParseError (show errors)+  toOutputT genOutput out =+    case genOutput of+    GenStdOut ->+      liftIO $ T.putStrLn out+    GenOutputFile fp ->+      liftIO $ T.writeFile fp out+  toOutputBSL genOutput out =+    case genOutput of+    GenStdOut ->+      liftIO $ BSL.putStr out+    GenOutputFile fp ->+      liftIO $ BSL.writeFile fp out+  toOutputBS genOutput out =+    case genOutput of+    GenStdOut ->+      liftIO $ BS.putStr out+    GenOutputFile fp ->+      liftIO $ BS.writeFile fp out+  runLogger = flip runReaderT leanAppstate+  runLean = flip runReaderT leanAppstate . runE @GenerateEffects++#endif
+ lib-opt/GHCup/OptParse/HealthCheck.hs view
@@ -0,0 +1,160 @@+{-# LANGUAGE CPP               #-}+{-# LANGUAGE DataKinds         #-}+{-# LANGUAGE TypeApplications  #-}+{-# LANGUAGE FlexibleContexts  #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes       #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE RankNTypes #-}++module GHCup.OptParse.HealthCheck where+++import GHCup.OptParse.Common++import GHCup.Command.HealthCheck+import GHCup.Errors+import GHCup.Input.Parsers+    ( toolParser )+import GHCup.Prelude.Logger+import GHCup.Prelude.String.QQ+import GHCup.Types++#if !MIN_VERSION_base(4,13,0)+import           Control.Monad.Fail             ( MonadFail )+#endif+import           Control.Monad.Reader+import           Control.Monad.Trans.Resource+import           Data.Functor+import           Data.Variant.Excepts+import           Options.Applicative     hiding ( style )+import           Prelude                 hiding ( appendFile )+import           System.Exit+import Options.Applicative.Pretty.Shim ( text )+import Text.PrettyPrint.HughesPJClass (prettyShow)+import Control.Exception.Safe (MonadMask)++import qualified Data.Text                     as T++++++    ----------------+    --[ Commands ]--+    ----------------+++data HealthCheckCommand+  = HealthCheckTool ToolOptions+  deriving (Eq, Show)+++++    ---------------+    --[ Options ]--+    ---------------+++data ToolOptions = ToolOptions+  { checkTool :: Tool+  , checkVer :: TargetVersion+  }+  deriving (Eq, Show)+++++    ---------------+    --[ Parsers ]--+    ---------------+++hcP :: Parser HealthCheckCommand+hcP =+  subparser+      (  command+          "tool"+          (   HealthCheckTool+          <$> info+                (toolOpts <**> helper)+                (  progDesc "Check tool for problems"+                <> footerDoc (Just $ text toolFooter)+                )+          )+      )+ where+  toolFooter :: String+  toolFooter = [s|Discussion:+  Check a tool for problems.++Examples:+  ghcup check tool |]++toolOpts :: Parser ToolOptions+toolOpts =+  (\t v -> ToolOptions t v)+    <$> argument (eitherReader toolParser) (metavar "TOOL" <> help "Which tool to install")+    <*> ghcVersionArgument [] Nothing+++    --------------+    --[ Footer ]--+    --------------+++hcFooter :: String+hcFooter = [s|Discussion:+  Performs various health checks. Good for attaching to bug reports.|]+++++    ---------------------------+    --[ Effect interpreters ]--+    ---------------------------+++type HCEffects = '[ ]+++++    ------------------+    --[ Entrypoint ]--+    ------------------++++hc :: ( Monad m+      , MonadMask m+      , MonadUnliftIO m+      , MonadFail m+      )+   => HealthCheckCommand+   -> (IO (AppState, IO ()), LeanAppState)+   -> m ExitCode+hc command' (getAppState', leanAppstate) = run (do+     case command' of+       HealthCheckTool ToolOptions{..} ->+         lift $ dbHealthCheck checkTool checkVer+   ) >>= \case+            (VRight r, up) -> do+              liftIO $ putStr $ prettyShow r+              liftIO up+              pure ExitSuccess+            (VLeft e, _) -> do+              runLogger $ logError $ T.pack $ prettyHFError e+              pure $ ExitFailure 27+ where+  runLogger = flip runReaderT leanAppstate+  run action' = do+    (appstate', up) <- liftIO getAppState'+    r <- flip runReaderT appstate'+                  . runResourceT+                  . runE+                    @HCEffects+                  $ action'+    pure (r, up)+
lib-opt/GHCup/OptParse/Install.hs view
@@ -1,48 +1,53 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE TypeApplications  #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE TemplateHaskell   #-}-{-# LANGUAGE QuasiQuotes       #-}-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DuplicateRecordFields #-}-{-# LANGUAGE ViewPatterns      #-}-{-# LANGUAGE TypeOperators     #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}  module GHCup.OptParse.Install where    -import           GHCup.OptParse.Common--import           GHCup-import           GHCup.Errors-import           GHCup.Types-import           GHCup.Utils.Dirs-import           GHCup.Utils.Parsers (fromVersion, isolateParser, uriParser)-import           GHCup.Prelude-import           GHCup.Prelude.Logger-import           GHCup.Prelude.String.QQ+import GHCup.Command.Install+import GHCup.Command.Set+import GHCup.Errors+import GHCup.Input.Parsers+    ( installTargetParser+    , isolateParser+    , resolveVersion+    , toolParser+    , uriParser+    )+import GHCup.OptParse.Common+import GHCup.Prelude+import GHCup.Prelude.String.QQ+import GHCup.Query.GHCupDirs+import GHCup.Query.Metadata+import GHCup.Types+import GHCup.Types.Optics -import           Control.Concurrent (threadDelay)+import Control.Concurrent ( threadDelay ) #if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )+import Control.Monad.Fail ( MonadFail ) #endif-import           Control.Monad (when, forM_)-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-import           Data.Either-import           Data.Functor-import           Data.Maybe-import           Data.Variant.Excepts-import           Options.Applicative     hiding ( style )-import           Options.Applicative.Pretty.Shim ( text )-import           Prelude                 hiding ( appendFile )-import           System.Exit-import           URI.ByteString          hiding ( uriParser )+import Control.Monad                   ( forM_, when )+import Control.Monad.Reader+import Control.Monad.Trans.Resource+import Data.Functor+import Data.Maybe+import Data.Variant.Excepts+import Options.Applicative             hiding ( style )+import Options.Applicative.Pretty.Shim ( text )+import Prelude                         hiding ( appendFile )+import System.Exit+import Text.PrettyPrint.HughesPJClass  ( prettyShow )+import URI.ByteString                  hiding ( uriParser ) -import qualified Data.Text                     as T+import qualified Data.Text as T   @@ -52,11 +57,13 @@     ----------------  -data InstallCommand = InstallGHC InstallOptions-                    | InstallCabal InstallOptions-                    | InstallHLS InstallOptions-                    | InstallStack InstallOptions-                    deriving (Eq, Show)+data InstallCommand+  = InstallGHC InstallOptions+  | InstallCabal InstallOptions+  | InstallHLS InstallOptions+  | InstallStack InstallOptions+  | InstallOtherTool InstallOptionsNew+  deriving (Eq, Show)   @@ -66,17 +73,30 @@     ---------------  data InstallOptions = InstallOptions-  { instVer      :: Maybe ToolVersion-  , instBindist  :: Maybe URI-  , instSet      :: Bool-  , isolateDir   :: Maybe FilePath+  { instVer :: Maybe ToolVersion+  , instBindist :: Maybe URI+  , instSet :: Bool+  , isolateDir :: Maybe FilePath   , forceInstall :: Bool-  , installTargets :: T.Text-  , addConfArgs  :: [T.Text]-  } deriving (Eq, Show)+  , installTargets :: Maybe [String]+  , addConfArgs :: [String]+  }+  deriving (Eq, Show) +data InstallOptionsNew = InstallOptionsNew+  { instTool :: Tool+  , instVer :: Maybe ToolVersion+  , instBindist :: Maybe URI+  , instSet :: Bool+  , isolateDir :: Maybe FilePath+  , forceInstall :: Bool+  , installTargets :: Maybe [String]+  , addConfArgs :: [String]+  }+  deriving (Eq, Show)  +     ---------------     --[ Footers ]--     ---------------@@ -95,14 +115,14 @@     --[ Parsers ]--     --------------- -installParser :: Parser (Either InstallCommand InstallOptions)+installParser :: Parser InstallCommand installParser =-  (Left <$> subparser+  subparser       (  command           "ghc"           (   InstallGHC           <$> info-                (installOpts (Just GHC) <**> helper)+                (installOpts (Just ghc) <**> helper)                 (  progDesc "Install GHC"                 <> footerDoc (Just $ text installGHCFooter)                 )@@ -111,7 +131,7 @@            "cabal"            (   InstallCabal            <$> info-                 (installOpts (Just Cabal) <**> helper)+                 (installOpts (Just cabal) <**> helper)                  (  progDesc "Install Cabal"                  <> footerDoc (Just $ text installCabalFooter)                  )@@ -120,7 +140,7 @@            "hls"            (   InstallHLS            <$> info-                 (installOpts (Just HLS) <**> helper)+                 (installOpts (Just hls) <**> helper)                  (  progDesc "Install haskell-language-server"                  <> footerDoc (Just $ text installHLSFooter)                  )@@ -129,14 +149,15 @@            "stack"            (   InstallStack            <$> info-                 (installOpts (Just Stack) <**> helper)+                 (installOpts (Just stack) <**> helper)                  (  progDesc "Install stack"                  <> footerDoc (Just $ text installStackFooter)                  )            )       )-    )-    <|> (Right <$> installOpts (Just GHC))+    <|> ( InstallOtherTool+           <$> installOptsNew+           )  where   installHLSFooter :: String   installHLSFooter = [s|Discussion:@@ -187,7 +208,7 @@                     (eitherReader uriParser)                     (short 'u' <> long "url" <> metavar "BINDIST_URL" <> help                       "Install the specified version from this bindist"-                      <> completer (toolDlCompleter (fromMaybe GHC tool))+                      <> completer (toolDlCompleter (fromMaybe ghc tool))                     )                   )             <*> (Just <$> toolVersionTagArgument [] tool)@@ -208,20 +229,58 @@           )     <*> switch           (short 'f' <> long "force" <> help "Force install (THIS IS UNSAFE, only use it in Dockerfiles or CI)")-    <*> strOption+    <*> optional (option (eitherReader installTargetParser)            (  long "install-targets"            <> metavar "TARGETS"-           <> help "Space separated list of install targets (default: install)"+           <> help "Overwrite make based install targets"            <> completer (listCompleter ["install", "install_bin", "install_lib", "install_extra", "install_man", "install_docs", "install_data", "update_package_db"])-           <> value "install"            )+           )     <*> many (argument str (metavar "CONFIGURE_ARGS" <> help "Additional arguments to bindist configure, prefix with '-- ' (longopts)"))  where   setDefault = case tool of-    Nothing  -> False-    Just GHC -> False-    Just _   -> True+    Nothing           -> False+    Just (Tool "ghc") -> False+    Just _            -> True +installOptsNew :: Parser InstallOptionsNew+installOptsNew =+  (\t (u, v) -> InstallOptionsNew t v u)+    <$> argument (eitherReader toolParser) (metavar "TOOL" <> help "Which tool to install")+    <*> (   (   (,)+            <$> optional+                  (option+                    (eitherReader uriParser)+                    (short 'u' <> long "url" <> metavar "BINDIST_URL" <> help+                      "Install the specified version from this bindist"+                    )+                  )+            <*> (Just <$> toolVersionTagArgument [] Nothing)+            )+        <|> pure (Nothing, Nothing)+        )+    <*> fmap (fromMaybe False) (invertableSwitch "set" Nothing False+      (help "Set as active version after install"))+    <*> optional+          (option+           (eitherReader isolateParser)+           (  short 'i'+           <> long "isolate"+           <> metavar "DIR"+           <> help "install in an isolated absolute directory instead of the default one"+           <> completer (bashCompleter "directory")+           )+          )+    <*> switch+          (short 'f' <> long "force" <> help "Force install (THIS IS UNSAFE, only use it in Dockerfiles or CI)")+    <*> optional (option (eitherReader installTargetParser)+           (  long "install-targets"+           <> metavar "TARGETS"+           <> help "Overwrite make based install targets"+           <> completer (listCompleter ["install", "install_bin", "install_lib", "install_extra", "install_man", "install_docs", "install_data", "update_package_db"])+           )+           )+    <*> many (argument str (metavar "CONFIGURE_ARGS" <> help "Additional arguments to bindist configure, prefix with '-- ' (longopts)"))   @@ -243,162 +302,126 @@     --[ Effect interpreters ]--     --------------------------- + type InstallEffects = '[ AlreadyInstalled-                       , UnknownArchive                        , ArchiveResult-                       , FileDoesNotExistError-                       , CopyError-                       , NotInstalled-                       , DirNotEmpty-                       , NoDownload-                       , NotInstalled                        , BuildFailed-                       , TagNotFound-                       , DayNotFound+                       , CopyError                        , DigestError                        , ContentLengthError-                       , GPGError+                       , DirNotEmpty                        , DownloadFailed-                       , TarDirDoesNotExist+                       , FileAlreadyExistsError+                       , FileDoesNotExistError+                       , GPGError+                       , MergeFileTreeError                        , NextVerNotFound+                       , NoDownload                        , NoToolVersionSet-                       , FileAlreadyExistsError+                       , NotInstalled                        , ProcessError+                       , TagNotFound+                       , DayNotFound+                       , TarDirDoesNotExist                        , UninstallFailed-                       , MergeFileTreeError+                       , UnknownArchive                        , InstallSetError+                       , NoCompatiblePlatform+                       , GHCup.Errors.ParseError+                       , UnsupportedSetupCombo+                       , DistroNotFound+                       , NoCompatibleArch                        , URIParseError+                       , NoInstallInfo+                       , GHCup.Errors.ParseError+                       , MalformedInstallInfo                        ]  -runInstTool :: AppState-            -> Excepts InstallEffects (ResourceT (ReaderT AppState IO)) a-            -> IO (VEither InstallEffects a)-runInstTool appstate' =-  flip runReaderT appstate'-  . runResourceT-  . runE-    @InstallEffects --type InstallGHCEffects = '[ AlreadyInstalled-                          , ArchiveResult-                          , BuildFailed-                          , CopyError-                          , DigestError-                          , ContentLengthError-                          , DirNotEmpty-                          , DownloadFailed-                          , FileAlreadyExistsError-                          , FileDoesNotExistError-                          , GPGError-                          , MergeFileTreeError-                          , NextVerNotFound-                          , NoDownload-                          , NoToolVersionSet-                          , NotInstalled-                          , ProcessError-                          , TagNotFound-                          , DayNotFound-                          , TarDirDoesNotExist-                          , UninstallFailed-                          , UnknownArchive-                          , InstallSetError-                          , NoCompatiblePlatform-                          , GHCup.Errors.ParseError-                          , UnsupportedSetupCombo-                          , DistroNotFound-                          , NoCompatibleArch-                          , URIParseError-                          ]--runInstGHC :: AppState-           -> Excepts InstallGHCEffects (ResourceT (ReaderT AppState IO)) a-           -> IO (VEither InstallGHCEffects a)-runInstGHC appstate' =-  flip runReaderT appstate'-  . runResourceT-  . runE-    @InstallGHCEffects--     -------------------     --[ Entrypoints ]--     -------------------  -install :: Either InstallCommand InstallOptions -> Settings -> IO AppState -> (ReaderT LeanAppState IO () -> IO ()) -> IO ExitCode-install installCommand settings getAppState' runLogger = case installCommand of-  (Right iGHCopts) -> do-    runLogger (logWarn "This is an old-style command for installing GHC. Use 'ghcup install ghc' instead.")-    installGHC iGHCopts-  (Left (InstallGHC iGHCopts)) -> installGHC iGHCopts-  (Left (InstallCabal iopts))  -> installCabal iopts-  (Left (InstallHLS iopts))    -> installHLS iopts-  (Left (InstallStack iopts))  -> installStack iopts+install :: InstallCommand -> Settings -> (IO (AppState, IO ()), LeanAppState) -> IO ExitCode+install installCommand settings (getAppState', leanAppstate) = case installCommand of+  (InstallGHC iGHCopts)    -> installOther (toInstallOptionsNew ghc iGHCopts)+  (InstallCabal iopts)     -> installOther (toInstallOptionsNew cabal iopts)+  (InstallHLS iopts)       -> installOther (toInstallOptionsNew hls iopts)+  (InstallStack iopts)     -> installOther (toInstallOptionsNew stack iopts)+  (InstallOtherTool iopts) -> installOther iopts  where   guessMode = if guessVersion settings then GLax else GStrict-  installGHC :: InstallOptions -> IO ExitCode-  installGHC InstallOptions{..} = do-    s'@AppState{ dirs = Dirs{ .. } } <- liftIO getAppState'++  toInstallOptionsNew instTool InstallOptions{..} = InstallOptionsNew{..}++  installOther :: InstallOptionsNew -> IO ExitCode+  installOther InstallOptionsNew{..} = do+    (s'@AppState{ dirs = Dirs{ .. } }, updateCheckAction) <- getAppState'     (case instBindist of-       Nothing -> runInstGHC s' $ do-         (v, vi) <- liftE $ fromVersion instVer guessMode GHC-         forM_ (_viPreInstall =<< vi) $ \msg -> do+       Nothing -> run s' $ do+         GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo+         treq@(TargetVersionReq tver _) <- liftE $ resolveVersion instVer guessMode instTool+         let vm = getVersionMetadata tver instTool dls+         forM_ (_vmPreInstall =<< vm) $ \msg -> do            lift $ logWarn msg            lift $ logWarn              "...waiting for 5 seconds, you can still abort..."            liftIO $ threadDelay 5000000 -- give the user a sec to intervene-         liftE $ runBothE' (installGHCBin-                     v-                     (maybe GHCupInternal IsolateDir isolateDir)-                     forceInstall-                     addConfArgs-                     installTargets-                   )-                   $ when instSet $ when (isNothing isolateDir) $ liftE $ void $ setGHC v SetGHCOnly Nothing-         pure vi+         -- TODO: install targets+         liftE $ runBothE' (installTool+                                    instTool+                                    treq+                                    (maybe GHCupInternal IsolateDir isolateDir)+                                    forceInstall+                                    addConfArgs+                                    installTargets+                                  ) $ when instSet $ when (isNothing isolateDir) $ liftE $ void $ setToolVersion instTool tver+         pure vm        Just uri -> do-         runInstGHC s'{ settings = settings {noVerify = True}} $ do-           (v, vi) <- liftE $ fromVersion instVer guessMode GHC-           forM_ (_viPreInstall =<< vi) $ \msg -> do+         run s'{ settings = settings {noVerify = True}} $ do+           pfreq <- lift getPlatformReq+           GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo+           (TargetVersionReq tver _) <- liftE $ resolveVersion instVer guessMode instTool+           let vm = getVersionMetadata tver instTool dls+           forM_ (_vmPreInstall =<< vm) $ \msg -> do              lift $ logWarn msg              lift $ logWarn                "...waiting for 5 seconds, you can still abort..."              liftIO $ threadDelay 5000000 -- give the user a sec to intervene-           liftE $ runBothE' (installGHCBindist-                       (DownloadInfo ((decUTF8Safe . serializeURIRef') uri) (Just $ RegexDir "ghc-.*") "" Nothing Nothing Nothing)-                       v+           liftE $ runBothE' (do+                     (rev, _) <- liftE $ getDownloadInfoE' instTool (TargetVersionReq tver Nothing)+                     installBindist+                       instTool+                       Nothing+                       (DownloadInfo ((decUTF8Safe . serializeURIRef') uri) regexDir "" Nothing Nothing Nothing (toInstallationInputSpec <$> defaultToolInstallSpec instTool pfreq tver))+                       (TargetVersionRev tver rev)                        (maybe GHCupInternal IsolateDir isolateDir)                        forceInstall                        addConfArgs                        installTargets                      )-                     $ when instSet $ when (isNothing isolateDir) $ liftE $ void $ setGHC v SetGHCOnly Nothing-           pure vi+                     $ when instSet $ when (isNothing isolateDir) $ liftE $ void $ setToolVersion instTool tver+           pure vm       )         >>= \case-              VRight vi -> do-                runLogger $ logInfo "GHC installation successful"-                forM_ (_viPostInstall =<< vi) $ \msg ->+              VRight vm -> do+                runLogger $ logInfo $ T.pack (prettyShow instTool) <> " installation successful"+                forM_ (_vmPostInstall =<< vm) $ \msg ->                   runLogger $ logInfo msg+                liftIO updateCheckAction                 pure ExitSuccess                VLeft e@(V (AlreadyInstalled _ _)) -> do                 runLogger $ logWarn $ T.pack $ prettyHFError e-                pure ExitSuccess-              VLeft e@(V (AlreadyInstalled _ _)) -> do-                runLogger $ logWarn $ T.pack $ prettyHFError e+                liftIO updateCheckAction                 pure ExitSuccess                VLeft (V (DirNotEmpty fp)) -> do                 runLogger $ logError $                   "Install directory " <> T.pack fp <> " is not empty."                 pure $ ExitFailure 3-              VLeft (V (DirNotEmpty fp)) -> do-                runLogger $ logError $-                  "Install directory " <> T.pack fp <> " is not empty."-                pure $ ExitFailure 3                VLeft err@(V (BuildFailed tmpdir _)) -> do                 case keepDirs settings of@@ -407,195 +430,23 @@                     "Check the logs at " <> T.pack (fromGHCupPath logsDir) <> " and the build directory " <> T.pack tmpdir <> " for more clues." <> "\n" <>                     "Make sure to clean up " <> T.pack tmpdir <> " afterwards.")                 pure $ ExitFailure 3-              VLeft err@(V (BuildFailed tmpdir _)) -> do-                case keepDirs settings of-                  Never -> runLogger (logError $ T.pack $ prettyHFError err)-                  _ -> runLogger (logError $ T.pack (prettyHFError err) <> "\n" <>-                    "Check the logs at " <> T.pack (fromGHCupPath logsDir) <> " and the build directory " <> T.pack tmpdir <> " for more clues." <> "\n" <>-                    "Make sure to clean up " <> T.pack tmpdir <> " afterwards.")-                pure $ ExitFailure 3                VLeft e -> do                 runLogger $ do                   logError $ T.pack $ prettyHFError e                   logError $ "Also check the logs in " <> T.pack (fromGHCupPath logsDir)                 pure $ ExitFailure 3---  installCabal :: InstallOptions -> IO ExitCode-  installCabal InstallOptions{..} = do-    s'@AppState{ dirs = Dirs{ .. } } <- liftIO getAppState'-    (case instBindist of-       Nothing -> runInstTool s' $ do-         (_tvVersion -> v, vi) <- liftE $ fromVersion instVer guessMode Cabal-         forM_ (_viPreInstall =<< vi) $ \msg -> do-           lift $ logWarn msg-           lift $ logWarn-             "...waiting for 5 seconds, you can still abort..."-           liftIO $ threadDelay 5000000 -- give the user a sec to intervene-         liftE $ runBothE' (installCabalBin-                                    v-                                    (maybe GHCupInternal IsolateDir isolateDir)-                                    forceInstall-                                  ) $ when instSet $ when (isNothing isolateDir) $ liftE $ setCabal v-         pure vi-       Just uri -> do-         runInstTool s'{ settings = settings { noVerify = True}} $ do-           (_tvVersion -> v, vi) <- liftE $ fromVersion instVer guessMode Cabal-           forM_ (_viPreInstall =<< vi) $ \msg -> do-             lift $ logWarn msg-             lift $ logWarn-               "...waiting for 5 seconds, you can still abort..."-             liftIO $ threadDelay 5000000 -- give the user a sec to intervene-           liftE $ runBothE' (installCabalBindist-                                      (DownloadInfo ((decUTF8Safe . serializeURIRef') uri) Nothing "" Nothing Nothing Nothing)-                                      v-                                      (maybe GHCupInternal IsolateDir isolateDir)-                                      forceInstall-                                    ) $ when instSet $ when (isNothing isolateDir) $ liftE $ setCabal v-           pure vi-      )-      >>= \case-            VRight vi -> do-              runLogger $ logInfo "Cabal installation successful"-              forM_ (_viPostInstall =<< vi) $ \msg ->-                runLogger $ logInfo msg-              pure ExitSuccess-            VLeft e@(V (AlreadyInstalled _ _)) -> do-              runLogger $ logWarn $ T.pack $ prettyHFError e-              pure ExitSuccess-            VLeft (V (FileAlreadyExistsError fp)) -> do-              runLogger $ logWarn $-                "File " <> T.pack fp <> " already exists. Use 'ghcup install cabal --isolate " <> T.pack fp <> " --force ..." <> "' if you want to overwrite."-              pure $ ExitFailure 3-            VLeft e@(V (AlreadyInstalled _ _)) -> do-              runLogger $ logWarn $ T.pack $ prettyHFError e-              pure ExitSuccess-            VLeft (V (FileAlreadyExistsError fp)) -> do-              runLogger $ logWarn $-                "File " <> T.pack fp <> " already exists. Use 'ghcup install cabal --isolate " <> T.pack fp <> " --force ..." <> "' if you want to overwrite."-              pure $ ExitFailure 3-            VLeft e -> do-              runLogger $ do-                logError $ T.pack $ prettyHFError e-                logError $ "Also check the logs in " <> T.pack (fromGHCupPath logsDir)-              pure $ ExitFailure 4--  installHLS :: InstallOptions -> IO ExitCode-  installHLS InstallOptions{..} = do-     s'@AppState{ dirs = Dirs{ .. } } <- liftIO getAppState'-     (case instBindist of-       Nothing -> runInstTool s' $ do-         (_tvVersion -> v, vi) <- liftE $ fromVersion instVer guessMode HLS-         forM_ (_viPreInstall =<< vi) $ \msg -> do-           lift $ logWarn msg-           lift $ logWarn-             "...waiting for 5 seconds, you can still abort..."-           liftIO $ threadDelay 5000000 -- give the user a sec to intervene-         liftE $ runBothE' (installHLSBin-                                    v-                                    (maybe GHCupInternal IsolateDir isolateDir)-                                    forceInstall-                                  ) $ when instSet $ when (isNothing isolateDir) $ liftE $ setHLS v SetHLSOnly Nothing-         pure vi-       Just uri -> do-         runInstTool s'{ settings = settings { noVerify = True}} $ do-           (_tvVersion -> v, vi) <- liftE $ fromVersion instVer guessMode HLS-           forM_ (_viPreInstall =<< vi) $ \msg -> do-             lift $ logWarn msg-             lift $ logWarn-               "...waiting for 5 seconds, you can still abort..."-             liftIO $ threadDelay 5000000 -- give the user a sec to intervene-           -- TODO: support legacy-           liftE $ runBothE' (installHLSBindist-                                      (DownloadInfo ((decUTF8Safe . serializeURIRef') uri) (if isWindows then Nothing else Just (RegexDir "haskell-language-server-*")) "" Nothing Nothing Nothing)-                                      v-                                      (maybe GHCupInternal IsolateDir isolateDir)-                                      forceInstall-                                    ) $ when instSet $ when (isNothing isolateDir) $ liftE $ setHLS v SetHLSOnly Nothing-           pure vi-      )-      >>= \case-            VRight vi -> do-              runLogger $ logInfo "HLS installation successful"-              forM_ (_viPostInstall =<< vi) $ \msg ->-                runLogger $ logInfo msg-              pure ExitSuccess-            VLeft e@(V (AlreadyInstalled _ _)) -> do-              runLogger $ logWarn $ T.pack $ prettyHFError e-              pure ExitSuccess-            VLeft (V (FileAlreadyExistsError fp)) -> do-              runLogger $ logWarn $-                "File " <> T.pack fp <> " already exists. Use 'ghcup install hls --isolate " <> T.pack fp <> " --force ..." <> "' if you want to overwrite."-              pure $ ExitFailure 3-            VLeft e@(V (AlreadyInstalled _ _)) -> do-              runLogger $ logWarn $ T.pack $ prettyHFError e-              pure ExitSuccess-            VLeft (V (FileAlreadyExistsError fp)) -> do-              runLogger $ logWarn $-                "File " <> T.pack fp <> " already exists. Use 'ghcup install hls --isolate " <> T.pack fp <> " --force ..." <> "' if you want to overwrite."-              pure $ ExitFailure 3-            VLeft e -> do-              runLogger $ do-                logError $ T.pack $ prettyHFError e-                logError $ "Also check the logs in " <> T.pack (fromGHCupPath logsDir)-              pure $ ExitFailure 4+   where+    run appstate' =+      flip runReaderT (appstate' :: AppState)+      . runResourceT+      . runE+        @InstallEffects+    runLogger = flip runReaderT leanAppstate+    regexDir = case instTool of+                 (Tool "ghc") -> Just $ RegexDir "ghc-.*"+                 (Tool "cabal") -> Nothing+                 (Tool "stack") -> Nothing+                 (Tool "hls") -> if isWindows then Nothing else Just (RegexDir "haskell-language-server-*")+                 _ -> Nothing -- TODO -  installStack :: InstallOptions -> IO ExitCode-  installStack InstallOptions{..} = do-     s'@AppState{ dirs = Dirs{ .. } } <- liftIO getAppState'-     (case instBindist of-        Nothing -> runInstTool s' $ do-          (_tvVersion -> v, vi) <- liftE $ fromVersion instVer guessMode Stack-          forM_ (_viPreInstall =<< vi) $ \msg -> do-            lift $ logWarn msg-            lift $ logWarn-              "...waiting for 5 seconds, you can still abort..."-            liftIO $ threadDelay 5000000 -- give the user a sec to intervene-          liftE $ runBothE' (installStackBin-                                     v-                                     (maybe GHCupInternal IsolateDir isolateDir)-                                     forceInstall-                                   ) $ when instSet $ when (isNothing isolateDir) $ liftE $ setStack v-          pure vi-        Just uri -> do-          runInstTool s'{ settings = settings { noVerify = True}} $ do-            (_tvVersion -> v, vi) <- liftE $ fromVersion instVer guessMode Stack-            forM_ (_viPreInstall =<< vi) $ \msg -> do-              lift $ logWarn msg-              lift $ logWarn-                "...waiting for 5 seconds, you can still abort..."-              liftIO $ threadDelay 5000000 -- give the user a sec to intervene-            liftE $ runBothE' (installStackBindist-                                       (DownloadInfo ((decUTF8Safe . serializeURIRef') uri) Nothing "" Nothing Nothing Nothing)-                                       v-                                       (maybe GHCupInternal IsolateDir isolateDir)-                                       forceInstall-                                     ) $ when instSet $ when (isNothing isolateDir) $ liftE $ setStack v-            pure vi-      )-      >>= \case-            VRight vi -> do-              runLogger $ logInfo "Stack installation successful"-              forM_ (_viPostInstall =<< vi) $ \msg ->-                runLogger $ logInfo msg-              pure ExitSuccess-            VLeft e@(V (AlreadyInstalled _ _)) -> do-              runLogger $ logWarn $ T.pack $ prettyHFError e-              pure ExitSuccess-            VLeft (V (FileAlreadyExistsError fp)) -> do-              runLogger $ logWarn $-                "File " <> T.pack fp <> " already exists. Use 'ghcup install stack --isolate " <> T.pack fp <> " --force ..." <> "' if you want to overwrite."-              pure $ ExitFailure 3-            VLeft e@(V (AlreadyInstalled _ _)) -> do-              runLogger $ logWarn $ T.pack $ prettyHFError e-              pure ExitSuccess-            VLeft (V (FileAlreadyExistsError fp)) -> do-              runLogger $ logWarn $-                "File " <> T.pack fp <> " already exists. Use 'ghcup install stack --isolate " <> T.pack fp <> " --force ..." <> "' if you want to overwrite."-              pure $ ExitFailure 3-            VLeft e -> do-              runLogger $ do-                logError $ T.pack $ prettyHFError e-                logError $ "Also check the logs in " <> T.pack (fromGHCupPath logsDir)-              pure $ ExitFailure 4
lib-opt/GHCup/OptParse/List.hs view
@@ -5,20 +5,22 @@ {-# LANGUAGE QuasiQuotes       #-} {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-}  module GHCup.OptParse.List where    -import           GHCup+import           GHCup.Command.List+import           GHCup.Errors import           GHCup.Prelude import           GHCup.Types-import           GHCup.Utils.Parsers (dayParser, toolParser, criteriaParser)+import           GHCup.Input.Parsers (dayParser, toolParserWithGHCup, criteriaParser, revisionShowParser) import           GHCup.OptParse.Common import           GHCup.Prelude.String.QQ-import           GHCup.Utils.Output-import           GHCup.Utils.Pager+import           GHCup.Compat.Terminal+import           GHCup.Compat.Pager  #if !MIN_VERSION_base(4,13,0) import           Control.Monad.Fail             ( MonadFail )@@ -31,18 +33,20 @@ import           Data.Functor import           Data.Maybe import           Data.Time.Calendar             ( Day )+import           Data.Variant.Excepts import           Data.Versions import           Options.Applicative     hiding ( style ) import           Prelude                 hiding ( appendFile ) import           System.Exit import           System.Console.Pretty   hiding ( color )+import           Text.PrettyPrint.HughesPJClass (prettyShow)  import qualified Data.Text                     as T import qualified Data.Text.IO                  as T import qualified System.Console.Pretty         as Pretty import Control.Exception.Safe (MonadMask) import GHCup.Types.Optics-import GHCup.Prelude.Logger (logDebug)+import qualified Data.Map.Strict as M   @@ -54,14 +58,16 @@     ---------------  + data ListOptions = ListOptions-  { loTool     :: Maybe Tool-  , lCriteria  :: Maybe ListCriteria-  , lFrom      :: Maybe Day-  , lTo        :: Maybe Day-  , lHideOld   :: Bool-  , lShowNightly :: Bool-  , lRawFormat :: Bool+  { loTool         :: Maybe [Tool]+  , lCriteria      :: [ListCriteria]+  , lFrom          :: Maybe Day+  , lTo            :: Maybe Day+  , lHideOld       :: Bool+  , lShowNightly   :: Bool+  , lRawFormat     :: Bool+  , lShowRevisions :: ShowRevisions   } deriving (Eq, Show)  @@ -75,14 +81,16 @@ listOpts =   ListOptions     <$> optional+         (some           (option-            (eitherReader toolParser)+            (eitherReader toolParserWithGHCup)             (short 't' <> long "tool" <> metavar "<ghc|cabal|hls|stack>" <> help               "Tool to list versions for. Default is all"               <> completer toolCompleter             )           )-    <*> optional+        )+    <*> many           (option             (eitherReader criteriaParser)             (  short 'c'@@ -118,6 +126,13 @@     <*> switch           (short 'r' <> long "raw-format" <> help "More machine-parsable format"           )+    <*> option+          (eitherReader revisionShowParser)+          (long "show-revisions" <> help "How to show revisions (default: updates)"+              <> metavar "<updates|all|none>"+              <> completer revisionCompleter+              <> value ShowUpdates+          )       --------------@@ -142,9 +157,18 @@     -----------------  -printListResult :: (HasLog env , MonadReader env m, MonadIO m)-                => Bool -> PagerConfig -> Bool -> [ListResult] -> m ()-printListResult no_color (PagerConfig pList pCmd) raw lr = do+printListResult ::+  ( HasLog env+  , MonadReader env m+  , MonadIO m+  )+  => Bool+  -> ShowRevisions+  -> PagerConfig+  -> Bool+  -> ToolListResult+  -> m ()+printListResult no_color show_revisions (PagerConfig pList pCmd) raw lr = do    let     color | raw || no_color = (\_ x -> x)@@ -168,18 +192,28 @@           then x           else [color Green "", "Tool", "Version", "Tags", "Notes"] : x         )-        . fmap-            (\ListResult {..} ->+        . mconcat . fmap+            (\(lTool, (_, ls)) -> ls <&> \ListResult{..} ->               let marks = if-                    | lSet       -> (color Green (if isWindows then "IS" else "✔✔"))-                    | lInstalled -> (color Green (if isWindows then "I " else "✓ "))-                    | otherwise  -> (color Red   (if isWindows then "X " else "✗ "))+                   | lSet       -> (color Green (if isWindows then "IS" else "✔✔"))+                   | lInstalled -> (color Green (if isWindows then "I " else "✓ "))+                   | otherwise  -> (color Red   (if isWindows then "X " else "✗ "))               in                 (if raw then [] else [marks])-                  ++ [ fmap toLower . show $ lTool-                     , case lCross of-                       Nothing -> T.unpack . prettyVer $ lVer-                       Just c  -> T.unpack (c <> "-" <> prettyVer lVer)+                  ++ [ fmap toLower . prettyShow $ lTool+                     , let rev = case lRev of+                                   (rev', RevUpdate)+                                     | show_revisions == ShowNone -> ""+                                     | otherwise -> "-r" <> show rev'+                                   (rev', RevOutdated)+                                     | show_revisions == ShowNone -> ""+                                     | otherwise -> "-r" <> show rev'+                                   (rev', RevNormal)+                                     | show_revisions == ShowAll -> "-r" <> show rev'+                                     | otherwise -> ""+                       in case lCross of+                            Nothing -> T.unpack (prettyVer lVer) <> rev+                            Just c  -> T.unpack (c <> "-" <> prettyVer lVer) <> rev                      , intercalate "," (filter (/= "") . fmap printTag $ sort lTag)                      , intercalate ","                      $  (if hlsPowered@@ -196,7 +230,7 @@                         )                      ]             )-        $ lr+        $ M.toList lr   let cols =         foldr (\xs ys -> zipWith (:) xs ys) (repeat []) rows       lengths = fmap (maximum . fmap strWidth) cols@@ -226,19 +260,35 @@   -list :: ( Monad m-         , MonadMask m-         , MonadUnliftIO m-         , MonadFail m-         )-      => ListOptions-      -> Bool-      -> PagerConfig-      -> (ReaderT AppState m ExitCode -> m ExitCode)-      -> m ExitCode-list ListOptions{..} no_color pgc runAppState =-  runAppState (do-      l <- listVersions loTool (maybeToList lCriteria) lHideOld lShowNightly (lFrom, lTo)-      printListResult no_color pgc lRawFormat l+list ::+  ( Monad m+  , MonadMask m+  , MonadUnliftIO m+  , MonadFail m+  )+  => ListOptions+  -> Bool+  -> PagerConfig+  -> (IO (AppState, IO ()), LeanAppState)+  -> m ExitCode+list ListOptions{..} no_color pgc (getAppState', leanAppstate) = do+  r <- run $ do+      l <- listVersions loTool lCriteria lShowRevisions lHideOld lShowNightly (lFrom, lTo)+      lift $ printListResult no_color lShowRevisions pgc lRawFormat l+  case r of+    (VRight _, up) -> do+      liftIO up       pure ExitSuccess-    )+    (VLeft e, _) -> do+      runLogger $ logError $ T.pack $ prettyHFError e+      pure $ ExitFailure 44+ where+  runLogger = flip runReaderT leanAppstate+  run action' = do+    (appstate', up) <- liftIO getAppState'+    r <- flip runReaderT appstate'+                  . runResourceT+                  . runE+                    @'[GHCup.Errors.ParseError]+                  $ action'+    pure (r, up)
lib-opt/GHCup/OptParse/Nuke.hs view
@@ -11,7 +11,9 @@   -import           GHCup+import           GHCup.Command.List (ListResult(..), ListCriteria(..), listVersions)+import           GHCup.Command.Rm+import           GHCup.Command.Nuke import           GHCup.Errors import           GHCup.Types import           GHCup.Prelude.Logger@@ -19,20 +21,19 @@ #if !MIN_VERSION_base(4,13,0) import           Control.Monad.Fail             ( MonadFail ) #endif-import           Control.Monad (forM_, void)+import           Control.Exception.Safe (MonadMask)+import           Control.Concurrent (threadDelay)+import           Control.Monad (forM_) import           Control.Monad.Reader import           Control.Monad.Trans.Resource+import           Data.Foldable.WithIndex import           Data.Maybe import           Data.Variant.Excepts-import           Options.Applicative     hiding ( style )+import           Options.Applicative     hiding ( style, ParseError ) import           Prelude                 hiding ( appendFile ) import           System.Exit  import qualified Data.Text                     as T-import Control.Exception.Safe (MonadMask)-import Control.DeepSeq-import Control.Exception-import Control.Concurrent (threadDelay)   @@ -42,14 +43,7 @@     ---------------------------  -type NukeEffects = '[ NotInstalled, UninstallFailed ]---runNuke :: AppState-        -> Excepts NukeEffects (ReaderT AppState m) a-        -> m (VEither NukeEffects a)-runNuke s' =-  flip runReaderT s' . runE @NukeEffects+type NukeEffects = '[ NotInstalled, UninstallFailed, ParseError, MalformedInstallInfo ]   @@ -64,13 +58,10 @@         , MonadUnliftIO m         , MonadFail m         )-     => IO AppState-     -> (ReaderT LeanAppState m () -> m ())+     => (IO (AppState, IO ()), LeanAppState)      -> m ExitCode-nuke appState runLogger = do-  s' <- liftIO appState-  void $ liftIO $ evaluate $ force s'-  runNuke s' (do+nuke (getAppState', leanAppstate) = do+  run (do        lift $ logWarn "WARNING: This will remove GHCup and all installed components from your system."        lift $ logWarn "Waiting 10 seconds before commencing, if you want to cancel it, now would be the time."        liftIO $ threadDelay 10000000  -- wait 10s@@ -78,9 +69,9 @@        lift $ logInfo "Initiating Nuclear Sequence 🚀🚀🚀"        lift $ logInfo "Nuking in 3...2...1" -       lInstalled <- lift $ listVersions Nothing [ListInstalled True] False True (Nothing, Nothing)+       lInstalled' <- liftE $ listVersions Nothing [ListInstalled True] ShowNone False True (Nothing, Nothing) -       forM_ lInstalled (liftE . rmTool)+       iforM_ lInstalled' $ \tool (_, ls) -> forM_ ls $ \ListResult{..} -> liftE $ rmToolVersion tool (TargetVersion lCross lVer)         lift rmGhcupDirs @@ -97,3 +88,12 @@                 VLeft e -> do                   runLogger $ logError $ T.pack $ prettyHFError e                   pure $ ExitFailure 15+ where+  run action' = do+    (appstate', _) <- liftIO getAppState'+    flip runReaderT appstate'+                  . runResourceT+                  . runE+                    @NukeEffects+                  $ action'+  runLogger = flip runReaderT leanAppstate
lib-opt/GHCup/OptParse/Prefetch.hs view
@@ -3,7 +3,6 @@ {-# LANGUAGE TypeApplications  #-} {-# LANGUAGE FlexibleContexts  #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell   #-} {-# LANGUAGE QuasiQuotes       #-} {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE RankNTypes #-}@@ -11,10 +10,10 @@ module GHCup.OptParse.Prefetch where  -import           GHCup+import           GHCup.Command.Prefetch import           GHCup.Errors import           GHCup.Types-import           GHCup.Utils.Parsers (fromVersion)+import           GHCup.Input.Parsers (resolveVersion, toolParser) import           GHCup.Types.Optics import           GHCup.Prelude.File import           GHCup.Prelude.Logger@@ -30,7 +29,7 @@ import           Data.Functor import           Data.Maybe import           Data.Variant.Excepts-import           Options.Applicative     hiding ( style )+import           Options.Applicative     hiding ( style, ParseError ) import           Prelude                 hiding ( appendFile ) import           System.Exit @@ -50,6 +49,7 @@                      | PrefetchCabal PrefetchOptions (Maybe ToolVersion)                      | PrefetchHLS PrefetchOptions (Maybe ToolVersion)                      | PrefetchStack PrefetchOptions (Maybe ToolVersion)+                     | PrefetchTool PrefetchOptions (Maybe ToolVersion) Tool                      | PrefetchMetadata  @@ -62,7 +62,8 @@   data PrefetchOptions = PrefetchOptions {-  pfCacheDir :: Maybe FilePath+    pfSrc :: Bool+  , pfCacheDir :: Maybe FilePath }  data PrefetchGHCOptions = PrefetchGHCOptions {@@ -86,7 +87,7 @@           <$> (PrefetchGHCOptions                 <$> ( switch (short 's' <> long "source" <> help "Download source tarball instead of bindist") <**> helper )                 <*> optional (option str (short 'd' <> long "directory" <> help "directory to download into (default: ~/.ghcup/cache/)" <> completer (bashCompleter "directory"))))-          <*>  optional (toolVersionTagArgument [] (Just GHC)) )+          <*>  optional (toolVersionTagArgument [] (Just ghc)) )         ( progDesc "Download GHC assets for installation")       )       <>@@ -94,8 +95,11 @@       "cabal"       (info         (PrefetchCabal-          <$> fmap PrefetchOptions (optional (option str (short 'd' <> long "directory" <> help "directory to download into (default: ~/.ghcup/cache/)" <> completer (bashCompleter "directory"))))-          <*> ( optional (toolVersionTagArgument [] (Just Cabal)) <**> helper ))+           <$> (PrefetchOptions+                 <$> ( switch (short 's' <> long "source" <> help "Download source tarball instead of bindist") <**> helper )+                 <*> optional (option str (short 'd' <> long "directory" <> help "directory to download into (default: ~/.ghcup/cache/)" <> completer (bashCompleter "directory")))+               )+          <*> ( optional (toolVersionTagArgument [] (Just cabal)) <**> helper ))         ( progDesc "Download cabal assets for installation")       )       <>@@ -103,8 +107,11 @@       "hls"       (info         (PrefetchHLS-          <$> fmap PrefetchOptions (optional (option str (short 'd' <> long "directory" <> help "directory to download into (default: ~/.ghcup/cache/)" <> completer (bashCompleter "directory"))))-          <*> ( optional (toolVersionTagArgument [] (Just HLS)) <**> helper ))+           <$> (PrefetchOptions+                 <$> ( switch (short 's' <> long "source" <> help "Download source tarball instead of bindist") <**> helper )+                 <*> optional (option str (short 'd' <> long "directory" <> help "directory to download into (default: ~/.ghcup/cache/)" <> completer (bashCompleter "directory")))+               )+          <*> ( optional (toolVersionTagArgument [] (Just hls)) <**> helper ))         ( progDesc "Download HLS assets for installation")       )       <>@@ -112,8 +119,11 @@       "stack"       (info         (PrefetchStack-          <$> fmap PrefetchOptions (optional (option str (short 'd' <> long "directory" <> help "directory to download into (default: ~/.ghcup/cache/)" <> completer (bashCompleter "directory"))))-          <*> ( optional (toolVersionTagArgument [] (Just Stack)) <**> helper ))+           <$> (PrefetchOptions+                 <$> ( switch (short 's' <> long "source" <> help "Download source tarball instead of bindist") <**> helper )+                 <*> optional (option str (short 'd' <> long "directory" <> help "directory to download into (default: ~/.ghcup/cache/)" <> completer (bashCompleter "directory")))+               )+          <*> ( optional (toolVersionTagArgument [] (Just stack)) <**> helper ))         ( progDesc "Download stack assets for installation")       )       <>@@ -123,6 +133,14 @@         helper         ( progDesc "Download ghcup's metadata, needed for various operations")       )+  ) <|>+  ( (\o t v -> PrefetchTool o v t)+    <$> (PrefetchOptions+          <$> ( switch (short 's' <> long "source" <> help "Download source tarball instead of bindist") <**> helper )+          <*> optional (option str (short 'd' <> long "directory" <> help "directory to download into (default: ~/.ghcup/cache/)" <> completer (bashCompleter "directory")))+        )+    <*> argument (eitherReader toolParser) (metavar "TOOL" <> help "Which tool to prefetch")+    <*> optional (toolVersionTagArgument [] Nothing)   )  @@ -162,22 +180,13 @@                         , JSONError                         , FileDoesNotExistError                         , StackPlatformDetectError+                        , UnsupportedMetadataFormat                         , URIParseError+                        , ParseError                         ]  -runPrefetch :: MonadUnliftIO m-            => (ReaderT AppState m (VEither PrefetchEffects a) -> m (VEither PrefetchEffects a))-            -> Excepts PrefetchEffects (ResourceT (ReaderT AppState m)) a-            -> m (VEither PrefetchEffects a)-runPrefetch runAppState =-  runAppState-  . runResourceT-  . runE-    @PrefetchEffects --     ------------------     --[ Entrypoint ]--     ------------------@@ -191,41 +200,61 @@             )          => PrefetchCommand          -> Settings-         -> (forall a. ReaderT AppState m (VEither PrefetchEffects a) -> m (VEither PrefetchEffects a))-         -> (ReaderT LeanAppState m () -> m ())+         -> (IO (AppState, IO ()), LeanAppState)          -> m ExitCode-prefetch prefetchCommand settings runAppState runLogger =-  runPrefetch runAppState (do+prefetch prefetchCommand settings (getAppState', leanAppstate) =+  run (do     case prefetchCommand of       PrefetchGHC         (PrefetchGHCOptions pfGHCSrc pfCacheDir) mt -> do           forM_ pfCacheDir (liftIO . createDirRecursive')-          (v, _) <- liftE $ fromVersion mt guessMode GHC+          v <- liftE $ resolveVersion mt guessMode ghc           if pfGHCSrc-          then liftE $ fetchGHCSrc v pfCacheDir-          else liftE $ fetchToolBindist v GHC pfCacheDir-      PrefetchCabal PrefetchOptions {pfCacheDir} mt   -> do+          then liftE $ fetchToolSrc ghc v pfCacheDir+          else liftE $ fetchToolBindist v ghc pfCacheDir+      PrefetchCabal PrefetchOptions {pfSrc, pfCacheDir} mt   -> do         forM_ pfCacheDir (liftIO . createDirRecursive')-        (v, _) <- liftE $ fromVersion mt guessMode Cabal-        liftE $ fetchToolBindist v Cabal pfCacheDir-      PrefetchHLS PrefetchOptions {pfCacheDir} mt   -> do+        v <- liftE $ resolveVersion mt guessMode cabal+        if pfSrc+        then liftE $ fetchToolSrc cabal v pfCacheDir+        else liftE $ fetchToolBindist v cabal pfCacheDir+      PrefetchHLS PrefetchOptions {pfSrc, pfCacheDir} mt   -> do         forM_ pfCacheDir (liftIO . createDirRecursive')-        (v, _) <- liftE $ fromVersion mt guessMode HLS-        liftE $ fetchToolBindist v HLS pfCacheDir-      PrefetchStack PrefetchOptions {pfCacheDir} mt   -> do+        v <- liftE $ resolveVersion mt guessMode hls+        if pfSrc+        then liftE $ fetchToolSrc hls v pfCacheDir+        else liftE $ fetchToolBindist v hls pfCacheDir+      PrefetchStack PrefetchOptions {pfSrc, pfCacheDir} mt   -> do         forM_ pfCacheDir (liftIO . createDirRecursive')-        (v, _) <- liftE $ fromVersion mt guessMode Stack-        liftE $ fetchToolBindist v Stack pfCacheDir+        v <- liftE $ resolveVersion mt guessMode stack+        if pfSrc+        then liftE $ fetchToolSrc stack v pfCacheDir+        else liftE $ fetchToolBindist v stack pfCacheDir+      PrefetchTool PrefetchOptions {pfCacheDir} mt tool -> do+        forM_ pfCacheDir (liftIO . createDirRecursive')+        v <- liftE $ resolveVersion mt guessMode tool+        liftE $ fetchToolBindist v tool pfCacheDir       PrefetchMetadata -> do         pfreq <- lift getPlatformReq         _ <- liftE $ getDownloadsF pfreq         pure ""        ) >>= \case-                VRight _ -> do-                      pure ExitSuccess-                VLeft e -> do+                (VRight _, up) -> do+                  liftIO up+                  pure ExitSuccess+                (VLeft e, _) -> do                   runLogger $ logError $ T.pack $ prettyHFError e                   pure $ ExitFailure 15   where-   guessMode = if guessVersion settings then GLaxWithInstalled else GStrict+  guessMode = if guessVersion settings then GLaxWithInstalled else GStrict++  run action' = do+    (appstate', up) <- liftIO getAppState'+    r <- flip runReaderT appstate'+                  . runResourceT+                  . runE+                    @PrefetchEffects+                  $ action'+    pure (r, up)+  runLogger = flip runReaderT leanAppstate
+ lib-opt/GHCup/OptParse/Reset.hs view
@@ -0,0 +1,65 @@+module GHCup.OptParse.Reset where++import GHCup.Types (UserSettings(..))++-- UserSettingsKey constructors correspond to UserSettings fields+data UserSettingsKey+    = Cache+    | MetaCache+    | MetaMode+    | NoVerify+    | Verbose+    | KeepDirs+    | Downloader+    | KeyBindings+    | UrlSource+    | NoNetwork+    | GPGSetting+    | PlatformOverride+    | Mirrors+    | DefGHCConfOptions+    | Pager+    | GuessVersion+    deriving (Show, Eq)++toUserSettingsKey :: String -> Either String UserSettingsKey+toUserSettingsKey = \case+    "cache" -> Right Cache+    "meta-cache" -> Right MetaCache+    "meta-mode" -> Right MetaMode+    "no-verify" -> Right NoVerify+    "verbose" -> Right Verbose+    "keep-dirs" -> Right KeepDirs+    "downloader" -> Right Downloader+    "key-bindings" -> Right KeyBindings+    "url-source" -> Right UrlSource+    "no-network" -> Right NoNetwork+    "gpg-setting" -> Right GPGSetting+    "platform-override" -> Right PlatformOverride+    "mirrors" -> Right Mirrors+    "def-ghc-conf-options" -> Right DefGHCConfOptions+    "pager" -> Right Pager+    "guess-version" -> Right GuessVersion+    invalidString -> Left invalidString++resetUserConfig ::+    UserSettings -> UserSettingsKey -> UserSettings+resetUserConfig settings key = case key of+    Cache -> settings { uCache = Nothing }+    MetaCache -> settings { uMetaCache = Nothing }+    MetaMode -> settings { uMetaMode = Nothing }+    NoVerify -> settings { uNoVerify = Nothing }+    Verbose -> settings { uVerbose = Nothing }+    KeepDirs -> settings { uKeepDirs = Nothing }+    Downloader -> settings { uDownloader = Nothing }+    KeyBindings -> settings { uKeyBindings = Nothing }+    UrlSource -> settings { uUrlSource = Nothing }+    NoNetwork -> settings { uNoNetwork = Nothing }+    GPGSetting -> settings { uGPGSetting = Nothing }+    PlatformOverride -> settings { uPlatformOverride = Nothing }+    Mirrors -> settings { uMirrors = Nothing }+    DefGHCConfOptions -> settings { uDefGHCConfOptions = Nothing }+    Pager -> settings { uPager = Nothing }+    GuessVersion -> settings { uGuessVersion = Nothing }++
lib-opt/GHCup/OptParse/Rm.hs view
@@ -1,44 +1,46 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE TypeApplications  #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell   #-}-{-# LANGUAGE QuasiQuotes       #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ViewPatterns #-}  module GHCup.OptParse.Rm where    -import           GHCup-import           GHCup.Errors-import           GHCup.Types-import           GHCup.Types.Optics-import           GHCup.Utils-import           GHCup.Prelude.Logger-import           GHCup.Prelude.String.QQ-import           GHCup.OptParse.Common+import GHCup.Command.List+import GHCup.Command.Rm+import GHCup.Errors+import GHCup.Input.Parsers     ( ghcVersionEither, toolParser )+import GHCup.OptParse.Common+import GHCup.Prelude.Logger+import GHCup.Prelude.String.QQ+import GHCup.Query.Metadata+import GHCup.Types+import GHCup.Types.Optics  #if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )+import Control.Monad.Fail ( MonadFail ) #endif-import           Control.Monad (forM_)-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-import           Data.Functor-import           Data.Maybe-import           Data.Versions-import           Data.Variant.Excepts-import           Options.Applicative     hiding ( style )-import           Prelude                 hiding ( appendFile )-import           System.Exit-import           Text.PrettyPrint.HughesPJClass ( prettyShow )+import Control.Monad                  ( forM_, when )+import Control.Monad.Reader+import Control.Monad.Trans.Resource+import Data.Functor+import Data.Maybe+import Data.Variant.Excepts+import Data.Versions+import Options.Applicative            hiding ( ParseError, style )+import Prelude                        hiding ( appendFile )+import System.Exit+import Text.PrettyPrint.HughesPJClass ( prettyShow ) -import qualified Data.Text                     as T-import Control.Exception.Safe (MonadMask)+import           Control.Exception.Safe ( MonadMask )+import qualified Data.Text              as T   @@ -48,11 +50,13 @@     ----------------  -data RmCommand = RmGHC RmOptions-               | RmCabal Version-               | RmHLS Version-               | RmStack Version-               deriving (Eq, Show)+data RmCommand+  = RmGHC RmOptions+  | RmCabal Version+  | RmHLS Version+  | RmStack Version+  | RmOther RmOptionsNew+  deriving (Eq, Show)   @@ -63,53 +67,67 @@   data RmOptions = RmOptions-  { ghcVer :: GHCTargetVersion-  } deriving (Eq, Show)+  { ghcVer :: TargetVersion+  }+  deriving (Eq, Show) +data RmOptionsNew = RmOptionsNew+  { rmTool :: Tool+  , ghcVer :: TargetVersion+  }+  deriving (Eq, Show)   +     ---------------     --[ Parsers ]--     ---------------  -rmParser :: Parser (Either RmCommand RmOptions)+rmParser :: Parser RmCommand rmParser =-  (Left <$> subparser+  subparser       (  command           "ghc"-          (RmGHC <$> info (rmOpts (Just GHC) <**> helper) (progDesc "Remove GHC version"))+          (RmGHC <$> info (rmOpts (Just ghc) <**> helper) (progDesc "Remove GHC version"))       <> command            "cabal"            (   RmCabal-           <$> info (versionParser' [ListInstalled True] (Just Cabal) <**> helper)+           <$> info (versionParser' [ListInstalled True] (Just cabal) <**> helper)                     (progDesc "Remove Cabal version")            )       <> command            "hls"            (   RmHLS-           <$> info (versionParser' [ListInstalled True] (Just HLS) <**> helper)+           <$> info (versionParser' [ListInstalled True] (Just hls) <**> helper)                     (progDesc "Remove haskell-language-server version")            )       <> command            "stack"            (   RmStack-           <$> info (versionParser' [ListInstalled True] (Just Stack) <**> helper)+           <$> info (versionParser' [ListInstalled True] (Just stack) <**> helper)                     (progDesc "Remove stack version")            )       )-    )-    <|> (Right <$> rmOpts Nothing)+    <|> (   RmOther+           <$> rmOptsNew+           )    rmOpts :: Maybe Tool -> Parser RmOptions rmOpts tool = RmOptions <$> ghcVersionArgument [ListInstalled True] tool +rmOptsNew :: Parser RmOptionsNew+rmOptsNew = RmOptionsNew+  <$> argument (eitherReader toolParser) (metavar "TOOL")+  <*> argument (eitherReader ghcVersionEither) (metavar "VERSION")   ++     --------------     --[ Footer ]--     --------------@@ -129,7 +147,7 @@     ---------------------------  -type RmEffects = '[ NotInstalled, UninstallFailed ]+type RmEffects = '[ NotInstalled, UninstallFailed, ParseError, MalformedInstallInfo ]   runRm :: (ReaderT env m (VEither RmEffects a) -> m (VEither RmEffects a))@@ -153,82 +171,45 @@       , MonadUnliftIO m       , MonadFail m       )-   => Either RmCommand RmOptions-   -> (ReaderT AppState m (VEither RmEffects (Maybe VersionInfo))-       -> m (VEither RmEffects (Maybe VersionInfo)))-   -> (ReaderT LeanAppState m () -> m ())+   => RmCommand+   -> (IO (AppState, IO ()), LeanAppState)    -> m ExitCode-rm rmCommand runAppState runLogger = case rmCommand of-  (Right rmopts) -> do-    runLogger (logWarn "This is an old-style command for removing GHC. Use 'ghcup rm ghc' instead.")-    rmGHC' rmopts-  (Left (RmGHC rmopts)) -> rmGHC' rmopts-  (Left (RmCabal rmopts)) -> rmCabal' rmopts-  (Left (RmHLS rmopts)) -> rmHLS' rmopts-  (Left (RmStack rmopts)) -> rmStack' rmopts+rm rmCommand (getAppState', leanAppstate) = case rmCommand of+  (RmGHC rmopts) -> rmOther (toRmOptionsNew ghc rmopts)+  (RmCabal (RmOptions . mkTVer -> rmopts)) -> rmOther (toRmOptionsNew cabal rmopts)+  (RmHLS (RmOptions . mkTVer -> rmopts)) -> rmOther (toRmOptionsNew hls rmopts)+  (RmStack (RmOptions . mkTVer -> rmopts)) -> rmOther (toRmOptionsNew stack rmopts)+  (RmOther rmopts) -> rmOther rmopts   where-  rmGHC' RmOptions{..} =-    runRm runAppState (do-        liftE $-          rmGHCVer ghcVer-        GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-        pure (getVersionInfo ghcVer GHC dls)-      )-      >>= \case-            VRight vi -> do-              postRmLog (tVerToText ghcVer) GHC vi-              runLogger $ logGHCPostRm ghcVer-              pure ExitSuccess-            VLeft  e -> do-              runLogger $ logError $ T.pack $ prettyHFError e-              pure $ ExitFailure 7--  rmCabal' tv =-    runRm runAppState (do-        liftE $-          rmCabalVer tv-        GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-        pure (getVersionInfo (mkTVer tv) Cabal dls)-      )-      >>= \case-            VRight vi -> do-              postRmLog (prettyVer tv) Cabal vi-              pure ExitSuccess-            VLeft  e -> do-              runLogger $ logError $ T.pack $ prettyHFError e-              pure $ ExitFailure 15--  rmHLS' tv =-    runRm runAppState (do-        liftE $-          rmHLSVer tv-        GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-        pure (getVersionInfo (mkTVer tv) HLS dls)-      )-      >>= \case-            VRight vi -> do-              postRmLog (prettyVer tv) HLS vi-              pure ExitSuccess-            VLeft  e -> do-              runLogger $ logError $ T.pack $ prettyHFError e-              pure $ ExitFailure 15+  toRmOptionsNew rmTool RmOptions{..} = RmOptionsNew{..}+  runLogger = flip runReaderT leanAppstate+  run action' = do+    (appstate', up) <- liftIO getAppState'+    r <- flip runReaderT appstate'+                  . runResourceT+                  . runE+                    @RmEffects+                  $ action'+    pure (r, up) -  rmStack' tv =-    runRm runAppState (do+  rmOther RmOptionsNew{..} =+    run (do         liftE $-          rmStackVer tv+          rmToolVersion rmTool ghcVer         GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-        pure (getVersionInfo (mkTVer tv) Stack dls)+        pure (getVersionMetadata ghcVer rmTool dls)       )       >>= \case-            VRight vi -> do-              postRmLog (prettyVer tv) Stack vi+            (VRight vm, up) -> do+              postRmLog (tVerToText ghcVer) rmTool vm+              when (rmTool == ghc) $ runLogger $ logGHCPostRm ghcVer+              liftIO up               pure ExitSuccess-            VLeft  e -> do+            (VLeft e, _) -> do               runLogger $ logError $ T.pack $ prettyHFError e-              pure $ ExitFailure 15+              pure $ ExitFailure 7 -  postRmLog tv tool vi = runLogger $ do-    logInfo $ "Successfuly removed " <> T.pack (prettyShow tool) <> " " <> tv-    forM_ (_viPostRemove =<< vi) logInfo+  postRmLog tv tool vm = runLogger $ do+    logInfo $ "Successfully removed " <> T.pack (prettyShow tool) <> " " <> tv+    forM_ (_vmPostRemove =<< vm) logInfo
lib-opt/GHCup/OptParse/Run.hs view
@@ -1,53 +1,60 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE QuasiQuotes       #-}-{-# LANGUAGE TypeApplications  #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE RankNTypes        #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE TypeFamilies      #-}-{-# LANGUAGE ViewPatterns      #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ViewPatterns #-} module GHCup.OptParse.Run where  -import           GHCup-import           GHCup.Utils-import           GHCup.Utils.Parsers (fromVersion, ghcVersionTagEither, isolateParser, toolVersionTagEither)-import           GHCup.OptParse.Common-import           GHCup.Errors-import           GHCup.Types-import           GHCup.Types.Optics-import           GHCup.Prelude-import           GHCup.Prelude.File+import GHCup.Command.Install+import GHCup.Command.Install.LowLevel+import GHCup.Command.Set+import GHCup.Errors+import GHCup.Input.Parsers+import GHCup.Input.SymlinkSpec+import GHCup.Legacy.HLS               ( setHLS )+import GHCup.Legacy.Utils+import GHCup.OptParse.Common+import GHCup.Prelude+import GHCup.Query.DB+import GHCup.Query.GHCupDirs+import GHCup.System.Directory+import GHCup.Types+import GHCup.Types.Optics #ifdef IS_WINDOWS-import           GHCup.Prelude.Process-import           GHCup.Prelude.Process.Windows ( execNoMinGW, resolveExecutable )+import Data.Maybe                    ( fromMaybe )+import GHCup.Prelude.Process+import GHCup.Prelude.Process.Windows ( execNoMinGW, resolveExecutable ) #endif-import           GHCup.Prelude.Logger-import           GHCup.Prelude.String.QQ+import GHCup.Prelude.String.QQ -import           Control.Exception.Safe         ( MonadMask, MonadCatch )+import Control.Exception.Safe ( displayException, handle ) #if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )+import Control.Monad.Fail ( MonadFail ) #endif-import           Control.Monad (when, forM_, forM, unless)-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-import           Data.Functor-import           Data.Maybe (isNothing, fromMaybe)-import           Data.List                      ( intercalate )-import           Data.Variant.Excepts-import           Options.Applicative     hiding ( style )-import           Prelude                 hiding ( appendFile )-import           System.FilePath-import           System.Environment-import           System.Exit+import Control.Monad                  ( forM, forM_, when )+import Control.Monad.Reader+import Control.Monad.Trans.Resource+import Data.Data                      ( Proxy (..) )+import Data.Functor+import Data.List                      ( intercalate )+import Data.Maybe                     ( isNothing )+import Data.Variant.Excepts+import Options.Applicative            hiding ( ParseError, style )+import Prelude                        hiding ( appendFile )+import System.Environment+import System.Exit+import System.FilePath+import Text.PrettyPrint.HughesPJClass ( prettyShow ) -import qualified Data.Map.Strict               as Map-import qualified Data.Text                     as T+import qualified Data.Map.Strict as Map+import qualified Data.Text       as T #ifndef IS_WINDOWS-import qualified System.Posix.Process          as SPP+import qualified System.Posix.Process as SPP #endif-import Data.Versions ( prettyVer, Version )   @@ -60,16 +67,18 @@  data RunOptions = RunOptions   { runAppendPATH :: Bool-  , runInstTool'  :: Bool-  , runMinGWPath  :: Bool-  , runGHCVer     :: Maybe ToolVersion-  , runCabalVer   :: Maybe ToolVersion-  , runHLSVer     :: Maybe ToolVersion-  , runStackVer   :: Maybe ToolVersion-  , runBinDir     :: Maybe FilePath-  , runQuick      :: Bool-  , runCOMMAND    :: [String]-  } deriving (Eq, Show)+  , runInstTool' :: Bool+  , runMinGWPath :: Bool+  , runGHCVer :: Maybe ToolVersion+  , runCabalVer :: Maybe ToolVersion+  , runHLSVer :: Maybe ToolVersion+  , runStackVer :: Maybe ToolVersion+  , runToolVer :: [(Tool, ToolVersion)]+  , runBinDir :: Maybe FilePath+  , runQuick :: Bool+  , runCOMMAND :: [String]+  }+  deriving (Eq, Show)   @@ -92,34 +101,42 @@           (option             (eitherReader ghcVersionTagEither)             (metavar "GHC_VERSION" <> long "ghc" <> help "The ghc version"-            <> completer (tagCompleter GHC [])-            <> (completer $ versionCompleter [] GHC)+            <> completer (tagCompleter ghc [])+            <> completer (versionCompleter [] ghc)             )           )     <*> optional           (option             (eitherReader toolVersionTagEither)             (metavar "CABAL_VERSION" <> long "cabal" <> help "The cabal version"-            <> completer (tagCompleter Cabal [])-            <> (completer $ versionCompleter [] Cabal)+            <> completer (tagCompleter cabal [])+            <> completer (versionCompleter [] cabal)             )           )     <*> optional           (option             (eitherReader toolVersionTagEither)             (metavar "HLS_VERSION" <> long "hls" <> help "The HLS version"-            <> completer (tagCompleter HLS [])-            <> (completer $ versionCompleter [] HLS)+            <> completer (tagCompleter hls [])+            <> completer (versionCompleter [] hls)             )           )     <*> optional           (option             (eitherReader toolVersionTagEither)             (metavar "STACK_VERSION" <> long "stack" <> help "The stack version"-            <> completer (tagCompleter Stack [])-            <> (completer $ versionCompleter [] Stack)+            <> completer (tagCompleter stack [])+            <> completer (versionCompleter [] stack)             )           )+    <*> many+         ( option+            (eitherReader toolAndVersionParser)+            (metavar "TOOL,VERSION" <> long "tool" <> help "The tool and the version (separated by ',')"+            <> completer (tagCompleter stack [])+            <> completer (versionCompleter [] stack)+          )+         )     <*> optional           (option            (eitherReader isolateParser)@@ -194,33 +211,15 @@                    , DistroNotFound                    , NoCompatibleArch                    , URIParseError+                   , NoInstallInfo+                   , ParseError+                   , IncompatibleConfig+                   , MalformedInstallInfo                    ] -runLeanRUN :: (MonadUnliftIO m, MonadIO m)-           => LeanAppState-           -> Excepts RunEffects (ReaderT LeanAppState m) a-           -> m (VEither RunEffects a)-runLeanRUN leanAppstate =-    -- Don't use runLeanAppState here, which is disabled on windows.-    -- This is the only command on all platforms that doesn't need full appstate.-    flip runReaderT leanAppstate-    . runE-      @RunEffects -runRUN :: MonadUnliftIO m-      => IO AppState-      -> Excepts RunEffects (ResourceT (ReaderT AppState m)) a-      -> m (VEither RunEffects a)-runRUN appState action' = do-  s' <- liftIO appState-  flip runReaderT s'-    . runResourceT-    . runE-      @RunEffects-    $ action'  -     ------------------     --[ Entrypoint ]--     ------------------@@ -228,22 +227,16 @@   run :: forall m .-       ( MonadFail m-       , MonadMask m-       , MonadCatch m-       , MonadIO m-       , MonadUnliftIO m+       ( MonadIOish m        , Alternative m        )    => RunOptions    -> Settings-   -> IO AppState-   -> LeanAppState-   -> (ReaderT LeanAppState m () -> m ())+   -> (IO (AppState, IO ()), LeanAppState)    -> m ExitCode-run RunOptions{..} settings runAppState leanAppstate runLogger = do+run RunOptions{..} settings (getAppState', leanAppstate) = do    r <- if not runQuick-        then runRUN runAppState $ do+        then runRUN $ do          toolchain <- liftE resolveToolchainFull           -- oh dear@@ -252,13 +245,13 @@           liftE $ installToolChainFull toolchain tmp          pure tmp-        else runLeanRUN leanAppstate $ do+        else runLeanRUN $ do          toolchain <- resolveToolchain          tmp <- lift $ createTmpDir toolchain          liftE $ installToolChain toolchain tmp          pure tmp    case r of-         VRight tmp -> do+         VRight (fromInstallDir -> tmp) -> do            case runCOMMAND of              [] -> do                liftIO $ putStr tmp@@ -273,8 +266,8 @@ #else                resolvedCmd <- fmap (fromMaybe cmd) $ liftIO $ resolveExecutable cmd runMinGWPath                r' <- if runMinGWPath-                     then runLeanRUN leanAppstate $ liftE $ lEM @_ @'[ProcessError] $ exec resolvedCmd args Nothing (Just newEnv)-                     else runLeanRUN leanAppstate $ liftE $ lEM @_ @'[ProcessError] $ execNoMinGW resolvedCmd args Nothing (Just newEnv)+                     then runLeanRUN $ liftE $ lEM @_ @'[ProcessError] $ exec resolvedCmd args Nothing (Just newEnv)+                     else runLeanRUN $ liftE $ lEM @_ @'[ProcessError] $ execNoMinGW resolvedCmd args Nothing (Just newEnv)                case r' of                  VRight _ -> pure ExitSuccess                  VLeft e -> do@@ -289,64 +282,60 @@     guessMode = if guessVersion settings then GLaxWithInstalled else GStrict -   -- TODO: doesn't work for cross-   resolveToolchainFull :: ( MonadFail m-                           , MonadThrow m-                           , MonadIO m-                           , MonadCatch m-                           )+   resolveToolchainFull :: ( MonadIOish m )                         => Excepts                              '[ TagNotFound                               , DayNotFound                               , NextVerNotFound                               , NoToolVersionSet+                              , ParseError                               ] (ResourceT (ReaderT AppState m)) Toolchain    resolveToolchainFull = do          ghcVer <- forM runGHCVer $ \ver -> do-           (v, _) <- liftE $ fromVersion (Just ver) guessMode GHC-           pure v+           liftE $ resolveVersion (Just ver) guessMode ghc          cabalVer <- forM runCabalVer $ \ver -> do-           (v, _) <- liftE $ fromVersion (Just ver) guessMode Cabal-           pure (_tvVersion v)+           fmap toVersionReq' $ liftE $ resolveVersion (Just ver) guessMode cabal          hlsVer <- forM runHLSVer $ \ver -> do-           (v, _) <- liftE $ fromVersion (Just ver) guessMode HLS-           pure (_tvVersion v)+           fmap toVersionReq' $ liftE $ resolveVersion (Just ver) guessMode hls          stackVer <- forM runStackVer $ \ver -> do-           (v, _) <- liftE $ fromVersion (Just ver) guessMode Stack-           pure (_tvVersion v)+           fmap toVersionReq' $ liftE $ resolveVersion (Just ver) guessMode stack+         toolVer <- forM runToolVer $ \(tool, ver) -> do+           v <- liftE $ resolveVersion (Just ver) guessMode tool+           pure (tool, v)          pure Toolchain{..}     resolveToolchain = do          ghcVer <- case runGHCVer of             Just (GHCVersion v) -> pure $ Just v-            Just (ToolVersion v) -> pure $ Just (mkTVer v)+            Just (ToolVersion v) -> pure $ Just (toTargetVersionReq' v)             Nothing -> pure Nothing-            _ -> fail "Internal error"+            _ -> throwE $ IncompatibleConfig "Cannot resolve tags/dates in quick mode"          cabalVer <- case runCabalVer of-            Just (GHCVersion v) -> pure $ Just (_tvVersion v)+            Just (GHCVersion v) -> pure $ Just (toVersionReq' v)             Just (ToolVersion v) -> pure $ Just v             Nothing -> pure Nothing-            _ -> fail "Internal error"+            _ -> throwE $ IncompatibleConfig "Cannot resolve tags/dates in quick mode"          hlsVer <- case runHLSVer of-            Just (GHCVersion v) -> pure $ Just (_tvVersion v)+            Just (GHCVersion v) -> pure $ Just (toVersionReq' v)             Just (ToolVersion v) -> pure $ Just v             Nothing -> pure Nothing-            _ -> fail "Internal error"+            _ -> throwE $ IncompatibleConfig "Cannot resolve tags/dates in quick mode"          stackVer <- case runStackVer of-            Just (GHCVersion v) -> pure $ Just (_tvVersion v)+            Just (GHCVersion v) -> pure $ Just (toVersionReq' v)             Just (ToolVersion v) -> pure $ Just v             Nothing -> pure Nothing-            _ -> fail "Internal error"+            _ -> throwE $ IncompatibleConfig "Cannot resolve tags/dates in quick mode"+         toolVer <- forM runToolVer $ \(tool, tver) -> case tver of+            (GHCVersion v) -> pure (tool, v)+            (ToolVersion v) -> pure (tool, toTargetVersionReq' v)+            _ -> throwE $ IncompatibleConfig "Cannot resolve tags/dates in quick mode"          pure Toolchain{..} -   installToolChainFull :: ( MonadFail m-                           , MonadThrow m-                           , MonadIO m-                           , MonadCatch m+   installToolChainFull :: ( MonadIOish m                            , Alternative m                            )                         => Toolchain-                        -> FilePath+                        -> InstallDirResolved                         -> Excepts                              '[ TagNotFound                               , DayNotFound@@ -375,87 +364,158 @@                               , DistroNotFound                               , NoCompatibleArch                               , URIParseError+                              , NoInstallInfo+                              , ParseError+                              , FileDoesNotExistError+                              , MalformedInstallInfo                               ] (ResourceT (ReaderT AppState m)) ()    installToolChainFull Toolchain{..} tmp = do          case ghcVer of-           Just v -> do-             isInstalled <- lift $ checkIfToolInstalled' GHC v-             unless isInstalled $ when (runInstTool' && isNothing (_tvTarget v)) $ void $ liftE $ installGHCBin-               v+           Just treq@(TargetVersionReq tver _rev) -> do+             hideExcept' @AlreadyInstalled Proxy $ when (runInstTool' && isNothing (_tvTarget tver)) $ void $ installTool+               ghc+               treq                GHCupInternal                False                []-               (T.pack "install")-             setGHC' v tmp+               Nothing+             liftE $ setTool' ghc tver tmp            _ -> pure ()          case cabalVer of-           Just v -> do-             isInstalled <- lift $ checkIfToolInstalled' Cabal (mkTVer v)-             unless isInstalled $ when runInstTool' $ void $ liftE $ installCabalBin-               v+           Just vreq@(VersionReq v _rev) -> do+             hideExcept' @AlreadyInstalled Proxy $ when runInstTool' $ void $ installTool+               cabal+               (toTargetVersionReq' vreq)                GHCupInternal                False-             setCabal' v tmp+               []+               Nothing+             liftE $ setTool' cabal (mkTVer v) tmp            _ -> pure ()          case stackVer of-           Just v -> do-             isInstalled <- lift $ checkIfToolInstalled' Stack (mkTVer v)-             unless isInstalled $ when runInstTool' $ void $ liftE $ installStackBin-               v+           Just vreq@(VersionReq v _rev) -> do+             hideExcept' @AlreadyInstalled Proxy $ when runInstTool' $ void $ installTool+               stack+               (toTargetVersionReq' vreq)                GHCupInternal                False-             setStack' v tmp+               []+               Nothing+             liftE $ setTool' stack (mkTVer v) tmp            _ -> pure ()          case hlsVer of-           Just v -> do-             isInstalled <- lift $ checkIfToolInstalled' HLS (mkTVer v)-             unless isInstalled $ when runInstTool' $ void $ liftE $ installHLSBin-               v+           Just vreq@(VersionReq v _rev) -> do+             hideExcept' @AlreadyInstalled Proxy $ when runInstTool' $ void $ installTool+               hls+               (toTargetVersionReq' vreq)                GHCupInternal                False-             setHLS' v tmp+               []+               Nothing+             liftE $ setTool' hls (mkTVer v) tmp            _ -> pure ()+         forM_ toolVer $ \(t, treq@(TargetVersionReq tver _rev)) -> do+           hideExcept' @AlreadyInstalled Proxy $ when (runInstTool' && isNothing (_tvTarget tver)) $ void $ installTool+             t+             treq+             GHCupInternal+             False+             []+             Nothing+           liftE $ setTool' t tver tmp -   installToolChain :: ( MonadFail m-                       , MonadThrow m-                       , MonadIO m-                       , MonadCatch m+   installToolChain :: ( MonadIOish m                        )                     => Toolchain-                    -> FilePath-                    -> Excepts '[NotInstalled] (ReaderT LeanAppState m) ()+                    -> InstallDirResolved+                    -> Excepts '[ParseError, NotInstalled, MalformedInstallInfo] (ReaderT LeanAppState m) ()    installToolChain Toolchain{..} tmp = do          case ghcVer of-           Just v -> setGHC' v tmp-           _ -> pure ()+           Just (TargetVersionReq tver _rev) -> setTool' ghc tver tmp+           _                                 -> pure ()          case cabalVer of-           Just v -> setCabal' v tmp-           _ -> pure ()+           Just (VersionReq v _rev) -> setTool' cabal (mkTVer v) tmp+           _                        -> pure ()          case stackVer of-           Just v -> setStack' v tmp-           _ -> pure ()+           Just (VersionReq v _rev) -> setTool' stack (mkTVer v) tmp+           _                        -> pure ()          case hlsVer of-           Just v -> setHLS' v tmp-           _ -> pure ()+           Just (VersionReq v _rev) -> setTool' hls (mkTVer v) tmp+           _                        -> pure ()+         forM_ toolVer $ \(t, TargetVersionReq tver _rev) -> setTool' t tver tmp -   setGHC' v tmp = do-          void $ liftE $ setGHC v SetGHC_XYZ (Just tmp)-          void $ liftE $ setGHC v SetGHCOnly (Just tmp)-   setCabal' v tmp = do-          bin  <- liftE $ whereIsTool Cabal (mkTVer v)-          cbin <- liftIO $ canonicalizePath bin-          lift $ createLink (relativeSymlink tmp cbin) (tmp </> ("cabal" <.> exeExt))-   setStack' v tmp = do-          bin  <- liftE $ whereIsTool Stack (mkTVer v)-          cbin <- liftIO $ canonicalizePath bin-          lift $ createLink (relativeSymlink tmp cbin) (tmp </> ("stack" <.> exeExt))+   setTool' ::+     forall m1 env .+     ( MonadReader env m1+     , HasDirs env+     , HasPlatformReq env+     , HasLog env+     , MonadIOish m1+     )+     => Tool+     -> TargetVersion+     -> InstallDirResolved+     -> Excepts '[ParseError, NotInstalled, MalformedInstallInfo] m1 ()+   setTool' tool v tmp = do+     lift (runE @'[FileDoesNotExistError, ParseError, NoInstallInfo] (getSymlinkSpec' tool v)) >>= \case+       VRight symSpec -> do+         let tmp' = fromInstallDir tmp+         dest <- lift $ toolInstallDestination tool v+         liftE $ void $ symlinkBinaries (GHCupDir dest) symSpec tmp tool v+         liftE $ void $ setToolVersion' tool v (Just tmp')+       VLeft (V pe@(ParseError _)) -> fail $ prettyHFError pe+       VLeft _ -- legacy+         | tool == ghc -> do+             let tmp' = fromInstallDir tmp+             pfreq <- lift getPlatformReq+             symSpec <- forM (defaultGHCExeSymLinked pfreq v (ghcBinaries pfreq v)) (liftE . parseSymlinkSpec (_tvVersion v))+             dest <- lift $ toolInstallDestination tool v+             liftE $ void $ symlinkBinaries (GHCupDir dest) symSpec tmp tool v+             liftE $ void $ setToolVersion' tool v (Just tmp')+         -- we can't use 'symlinkBinaries' here for most tools, because+         -- it relies on everything residing within @~/.ghcup/<tool>@,+         -- which is not the case for early cabal/stack/hls+         | tool == cabal -> legacySet'+         | tool == stack -> legacySet'+         | tool == hls -> do+             let tmp' = fromInstallDir tmp+             setHLS' (_tvVersion v) tmp'+         | tool == ghcup -> do+             pure ()+         | otherwise ->+             throwE $ NotInstalled tool v+     pure ()+    where+     legacySet' = do+       let tmp' = fromInstallDir tmp+       Dirs {..}  <- getDirs+       let tool' = prettyShow tool+           pvpExe = tool' <> "-" <> prettyShow v <.> exeExt++       -- create <tool>-X.Y.Z+       target <- binarySymLinkDestination tmp' (binDir </> pvpExe)+       lift $ createLink target (tmp' </> pvpExe)++       -- create <tool>-X.Y+       lift $ handle+                (\(e :: ParseError) -> logWarn (T.pack $ displayException e))+             $ do+                (mj, mi) <- getMajorMinorV (_tvVersion v)+                let exeMajorMinor = tool' <> "-" <> T.unpack (intToText mj) <> "." <> T.unpack (intToText mi) <.> exeExt+                createLink pvpExe (tmp' </> exeMajorMinor)++       -- create <tool>+       liftE $ void $ setToolVersion' tool v (Just tmp')+++   -- TODO: legacy    setHLS' v tmp = do           Dirs {..}  <- getDirs           legacy <- isLegacyHLS v           if legacy           then do             -- TODO: factor this out-            hlsWrapper <- liftE @_ @'[NotInstalled] $ hlsWrapperBinary v !? (NotInstalled HLS (mkTVer v))+            hlsWrapper <- liftE @_ @'[NotInstalled] $ hlsWrapperBinary v !? NotInstalled hls (mkTVer v)             cw <- liftIO $ canonicalizePath (binDir </> hlsWrapper)             lift $ createLink (relativeSymlink tmp cw) (tmp </> takeFileName cw)             hlsBins <- hlsServerBinaries v Nothing >>= liftIO . traverse (canonicalizePath . (binDir </>))@@ -463,46 +523,57 @@               lift $ createLink (relativeSymlink tmp bin) (tmp </> takeFileName bin)             liftE $ setHLS v SetHLSOnly (Just tmp)           else do-            liftE $ setHLS v SetHLS_XYZ (Just tmp)-            liftE $ setHLS v SetHLSOnly (Just tmp)+            liftE $ void $ setToolVersion' hls (mkTVer v) (Just tmp) -   createTmpDir :: ( MonadUnliftIO m-                   , MonadCatch m-                   , MonadThrow m-                   , MonadMask m-                   , MonadIO m-                   )+   createTmpDir :: ( MonadIOish m )                 => Toolchain-                -> ReaderT LeanAppState m FilePath+                -> ReaderT LeanAppState m InstallDirResolved    createTmpDir toolchain =      case runBinDir of            Just bindir -> do              liftIO $ createDirRecursive' bindir-             liftIO $ canonicalizePath bindir+             fmap IsolateDirResolved $ liftIO $ canonicalizePath bindir            Nothing -> do              d <- predictableTmpDir toolchain-             liftIO $ createDirRecursive' d-             liftIO $ canonicalizePath d+             liftIO $ createDirRecursive' (fromGHCupPath d)+             pure $ GHCupDir d     predictableTmpDir :: Monad m                      => Toolchain-                     -> ReaderT LeanAppState m FilePath-   predictableTmpDir (Toolchain Nothing Nothing Nothing Nothing) = do+                     -> ReaderT LeanAppState m GHCupPath+   predictableTmpDir (Toolchain Nothing Nothing Nothing Nothing []) = do      Dirs { tmpDir } <- getDirs-     pure (fromGHCupPath tmpDir </> "ghcup-none")+     pure (tmpDir `appendGHCupPath` "ghcup-none")    predictableTmpDir Toolchain{..} = do       Dirs { tmpDir } <- getDirs-      pure $ fromGHCupPath tmpDir-        </> ("ghcup-" <> intercalate "_"-              (  maybe [] ( (:[]) . ("ghc-"   <>) . T.unpack . tVerToText) ghcVer-              <> maybe [] ( (:[]) . ("cabal-" <>) . T.unpack . prettyVer) cabalVer-              <> maybe [] ( (:[]) . ("hls-"   <>) . T.unpack . prettyVer) hlsVer-              <> maybe [] ( (:[]) . ("stack-" <>) . T.unpack . prettyVer) stackVer+      pure $ tmpDir+        `appendGHCupPath` ("ghcup-" <> intercalate "_"+              (  maybe [] ( (:[]) . ("ghc-"   <>) . prettyShow)        ghcVer+              <> maybe [] ( (:[]) . ("cabal-" <>) . prettyShow)        cabalVer+              <> maybe [] ( (:[]) . ("hls-"   <>) . prettyShow)        hlsVer+              <> maybe [] ( (:[]) . ("stack-" <>) . prettyShow)        stackVer+              <> fmap (\(t, v) -> prettyShow t <> "-" <> prettyShow v) toolVer               )             ) +   runLogger = flip runReaderT leanAppstate+   runLeanRUN :: forall m1 a . Excepts RunEffects (ReaderT LeanAppState m1) a -> m1 (VEither RunEffects a)+   runLeanRUN =+        -- Don't use runLeanAppState here, which is disabled on windows.+        -- This is the only command on all platforms that doesn't need full appstate.+        flip runReaderT leanAppstate+        . runE+          @RunEffects +   runRUN action' = do+     (appstate', _) <- liftIO getAppState'+     flip runReaderT appstate'+                   . runResourceT+                   . runE+                     @RunEffects+                   $ action' +     -------------------------     --[ Other local types ]--     -------------------------@@ -510,8 +581,10 @@   data Toolchain = Toolchain-  { ghcVer     :: Maybe GHCTargetVersion-  , cabalVer   :: Maybe Version-  , hlsVer     :: Maybe Version-  , stackVer   :: Maybe Version-  } deriving Show+  { ghcVer :: Maybe TargetVersionReq+  , cabalVer :: Maybe VersionReq+  , hlsVer :: Maybe VersionReq+  , stackVer :: Maybe VersionReq+  , toolVer :: [(Tool, TargetVersionReq)]+  }+  deriving (Show)
lib-opt/GHCup/OptParse/Set.hs view
@@ -1,46 +1,54 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE TypeApplications  #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE QuasiQuotes       #-}-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-}  module GHCup.OptParse.Set where    -import           GHCup.OptParse.Common+import GHCup.OptParse.Common -import           GHCup-import           GHCup.Errors-import           GHCup.Types-import           GHCup.Utils.Parsers (SetToolVersion(..), tagEither, ghcVersionEither, toolVersionEither, fromVersion')-import           GHCup.Prelude.Logger-import           GHCup.Prelude.String.QQ+import GHCup.Command.List+import GHCup.Command.Set+import GHCup.Errors+import GHCup.Input.Parsers+    ( SetToolVersion (..)+    , ghcVersionEither'+    , resolveVersion'+    , tagEither+    , toolParser+    , toolVersionEither'+    )+import GHCup.Prelude.Logger+import GHCup.Prelude.String.QQ+import GHCup.Types  #if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )+import Control.Monad.Fail ( MonadFail ) #endif-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-import           Data.Either-import           Data.Functor-import           Data.Maybe-import           Data.Versions-import           GHC.Unicode-import           Data.Variant.Excepts-import           Options.Applicative     hiding ( style )-import           Options.Applicative.Pretty.Shim ( text )-import           Prelude                 hiding ( appendFile )-import           System.Exit+import Control.Exception.Safe          ( MonadMask )+import Control.Monad.Reader+import Control.Monad.Trans.Resource+import Data.Bifunctor                  ( second )+import Data.Either+import Data.Functor+import Data.Maybe+import Data.Variant.Excepts+import Data.Versions+import GHC.Unicode+import Options.Applicative             hiding ( ParseError, style )+import Options.Applicative.Pretty.Shim ( text )+import Prelude                         hiding ( appendFile )+import System.Exit+import Text.PrettyPrint.HughesPJClass  ( prettyShow ) -import qualified Data.Text                     as T-import Data.Bifunctor (second)-import Control.Exception.Safe (MonadMask)-import GHCup.Types.Optics+import qualified Data.Text as T   @@ -50,11 +58,13 @@     ----------------  -data SetCommand = SetGHC SetOptions-                | SetCabal SetOptions-                | SetHLS SetOptions-                | SetStack SetOptions-                deriving (Eq, Show)+data SetCommand+  = SetGHC SetOptions+  | SetCabal SetOptions+  | SetHLS SetOptions+  | SetStack SetOptions+  | SetOther SetOptionsNew+  deriving (Eq, Show)   @@ -66,24 +76,31 @@  data SetOptions = SetOptions   { sToolVer :: SetToolVersion-  } deriving (Eq, Show)+  }+  deriving (Eq, Show) +data SetOptionsNew = SetOptionsNew+  { sTool :: Tool+  , sToolVer :: SetToolVersion+  }+  deriving (Eq, Show)   +     ---------------     --[ Parsers ]--     ---------------  -setParser :: Parser (Either SetCommand SetOptions)+setParser :: Parser SetCommand setParser =-  (Left <$> subparser+  subparser       (  command           "ghc"           (   SetGHC           <$> info-                (setOpts GHC <**> helper)+                (setOpts ghc <**> helper)                 (  progDesc "Set GHC version"                 <> footerDoc (Just $ text setGHCFooter)                 )@@ -92,7 +109,7 @@            "cabal"            (   SetCabal            <$> info-                 (setOpts Cabal <**> helper)+                 (setOpts cabal <**> helper)                  (  progDesc "Set Cabal version"                  <> footerDoc (Just $ text setCabalFooter)                  )@@ -101,7 +118,7 @@            "hls"            (   SetHLS            <$> info-                 (setOpts HLS <**> helper)+                 (setOpts hls <**> helper)                  (  progDesc "Set haskell-language-server version"                  <> footerDoc (Just $ text setHLSFooter)                  )@@ -110,14 +127,15 @@            "stack"            (   SetStack            <$> info-                 (setOpts Stack <**> helper)+                 (setOpts stack <**> helper)                  (  progDesc "Set stack version"                  <> footerDoc (Just $ text setStackFooter)                  )            )       )-    )-    <|> (Right <$> setOpts GHC)+    <|> (   SetOther+           <$> setOptsNew+           )  where   setGHCFooter :: String   setGHCFooter = [s|Discussion:@@ -139,10 +157,23 @@   setOpts :: Tool -> Parser SetOptions-setOpts tool = SetOptions <$>-    (fromMaybe SetRecommended <$>-      optional (setVersionArgument [ListInstalled True] tool))+setOpts tool =+    SetOptions . fromMaybe SetRecommended <$>+      optional (setVersionArgument [ListInstalled True] tool) +setOptsNew :: Parser SetOptionsNew+setOptsNew = SetOptionsNew+  <$> argument (eitherReader toolParser) (metavar "TOOL")+  <*> (fromMaybe SetRecommended <$> optional (argument (eitherReader setEither) (metavar "VERSION|TAG|next")))+ where+  setEither s' =+        parseSet s'+    <|> second SetToolTag (tagEither s')+    <|> second SetGHCVersion (ghcVersionEither' s')+  parseSet s' = case fmap toLower s' of+                  "next" -> Right SetNext+                  other  -> Left $ "Unknown tag/version " <> other+ setVersionArgument :: [ListCriteria] -> Tool -> Parser SetToolVersion setVersionArgument criteria tool =   argument (eitherReader setEither)@@ -155,8 +186,8 @@     <|> second SetToolTag (tagEither s')     <|> se s'   se s' = case tool of-           GHC -> second SetGHCVersion (ghcVersionEither s')-           _   -> second SetToolVersion (toolVersionEither s')+           Tool "ghc" -> second SetGHCVersion (ghcVersionEither' s')+           _          -> second SetToolVersion (toolVersionEither' s')   parseSet s' = case fmap toLower s' of                   "next" -> Right SetNext                   other  -> Left $ "Unknown tag/version " <> other@@ -183,65 +214,14 @@     ---------------------------  -type SetGHCEffects = '[ FileDoesNotExistError+type SetEffects = '[ FileDoesNotExistError                    , NotInstalled                    , TagNotFound                    , DayNotFound                    , NextVerNotFound-                   , NoToolVersionSet]--runSetGHC :: (ReaderT env m (VEither SetGHCEffects a) -> m (VEither SetGHCEffects a))-          -> Excepts SetGHCEffects (ReaderT env m) a-          -> m (VEither SetGHCEffects a)-runSetGHC runAppState =-    runAppState-    . runE-      @SetGHCEffects---type SetCabalEffects = '[ NotInstalled-                        , TagNotFound-                        , DayNotFound-                        , NextVerNotFound-                        , NoToolVersionSet]--runSetCabal :: (ReaderT env m (VEither SetCabalEffects a) -> m (VEither SetCabalEffects a))-            -> Excepts SetCabalEffects (ReaderT env m) a-            -> m (VEither SetCabalEffects a)-runSetCabal runAppState =-    runAppState-    . runE-      @SetCabalEffects---type SetHLSEffects = '[ NotInstalled-                      , TagNotFound-                      , DayNotFound-                      , NextVerNotFound-                      , NoToolVersionSet]--runSetHLS :: (ReaderT env m (VEither SetHLSEffects a) -> m (VEither SetHLSEffects a))-          -> Excepts SetHLSEffects (ReaderT env m) a-          -> m (VEither SetHLSEffects a)-runSetHLS runAppState =-    runAppState-    . runE-      @SetHLSEffects---type SetStackEffects = '[ NotInstalled-                        , TagNotFound-                        , DayNotFound-                        , NextVerNotFound-                        , NoToolVersionSet]--runSetStack :: (ReaderT env m (VEither SetStackEffects a) -> m (VEither SetStackEffects a))-            -> Excepts SetStackEffects (ReaderT env m) a-            -> m (VEither SetStackEffects a)-runSetStack runAppState =-    runAppState-    . runE-      @SetStackEffects+                   , NoToolVersionSet+                   , ParseError+                   ]   @@ -250,99 +230,52 @@     -------------------  -set :: forall m env.-       ( Monad m+set :: forall m. ( Monad m        , MonadMask m        , MonadUnliftIO m        , MonadFail m-       , HasDirs env-       , HasLog env        )-    => Either SetCommand SetOptions+    => SetCommand     -> Settings-    -> (forall eff . ReaderT AppState m (VEither eff GHCTargetVersion)-        -> m (VEither eff GHCTargetVersion))-    -> (forall eff. ReaderT env m (VEither eff GHCTargetVersion)-        -> m (VEither eff GHCTargetVersion))-    -> (ReaderT LeanAppState m () -> m ())+    -> (IO (AppState, IO ()), LeanAppState)     -> m ExitCode-set setCommand settings runAppState _ runLogger = case setCommand of-  (Right sopts) -> do-    runLogger (logWarn "This is an old-style command for setting GHC. Use 'ghcup set ghc' instead.")-    setGHC' sopts-  (Left (SetGHC sopts))   -> setGHC'   sopts-  (Left (SetCabal sopts)) -> setCabal' sopts-  (Left (SetHLS sopts))   -> setHLS'   sopts-  (Left (SetStack sopts)) -> setStack' sopts+set setCommand settings (getAppState', leanAppstate) = case setCommand of+  (SetGHC sopts)   -> setOther (toSetOptionsNew ghc sopts)+  (SetCabal sopts) -> setOther (toSetOptionsNew cabal sopts)+  (SetHLS sopts)   -> setOther (toSetOptionsNew hls sopts)+  (SetStack sopts) -> setOther (toSetOptionsNew stack sopts)+  (SetOther sopts) -> setOther sopts   where   guessMode = if guessVersion settings then GLaxWithInstalled else GStrict--  setGHC' :: SetOptions-          -> m ExitCode-  setGHC' SetOptions{ sToolVer } = runSetGHC runAppState (do-          v <- liftE $ fst <$> fromVersion' sToolVer guessMode GHC-          liftE $ setGHC v SetGHCOnly Nothing-        )-      >>= \case-            VRight GHCTargetVersion{..} -> do-              runLogger-                $ logInfo $-                    "GHC " <> prettyVer _tvVersion <> " successfully set as default version" <> maybe "" (" for cross target " <>) _tvTarget-              pure ExitSuccess-            VLeft e -> do-              runLogger $ logError $ T.pack $ prettyHFError e-              pure $ ExitFailure 5+  runLogger = flip runReaderT leanAppstate+  run action' = do+    (appstate', up) <- liftIO getAppState'+    r <- flip runReaderT appstate'+                  . runResourceT+                  . runE+                    @SetEffects+                  $ action'+    pure (r, up)  -  setCabal' :: SetOptions-            -> m ExitCode-  setCabal' SetOptions{ sToolVer } = runSetCabal runAppState (do-          v <- liftE $ fst <$> fromVersion' sToolVer guessMode Cabal-          liftE $ setCabal (_tvVersion v)-          pure v-        )-      >>= \case-            VRight v -> do-              runLogger-                $ logInfo $-                    "Cabal " <> prettyVer (_tvVersion v) <> " successfully set as default version"-              pure ExitSuccess-            VLeft  e -> do-              runLogger $ logError $ T.pack $ prettyHFError e-              pure $ ExitFailure 14+  toSetOptionsNew sTool SetOptions{..} = SetOptionsNew{..} -  setHLS' :: SetOptions-          -> m ExitCode-  setHLS' SetOptions{ sToolVer } = runSetHLS runAppState (do-          v <- liftE $ fst <$> fromVersion' sToolVer guessMode HLS-          liftE $ setHLS (_tvVersion v) SetHLSOnly Nothing-          pure v+  setOther :: SetOptionsNew+           -> m ExitCode+  setOther SetOptionsNew{ sTool, sToolVer } = run (do+          (TargetVersionReq v _) <- liftE $ resolveVersion' sToolVer guessMode sTool+          liftE $ setToolVersion sTool v         )       >>= \case-            VRight v -> do+            (VRight TargetVersion{..}, up) -> do               runLogger                 $ logInfo $-                    "HLS " <> prettyVer (_tvVersion v) <> " successfully set as default version"+                    T.pack (prettyShow sTool) <> " " <> prettyVer _tvVersion <> " successfully set as default version" <> maybe "" (" for cross target " <>) _tvTarget+              liftIO up               pure ExitSuccess-            VLeft  e -> do+            (VLeft e, _) -> do               runLogger $ logError $ T.pack $ prettyHFError e-              pure $ ExitFailure 14+              pure $ ExitFailure 5  -  setStack' :: SetOptions-            -> m ExitCode-  setStack' SetOptions{ sToolVer } = runSetStack runAppState (do-            v <- liftE $ fst <$> fromVersion' sToolVer guessMode Stack-            liftE $ setStack (_tvVersion v)-            pure v-          )-      >>= \case-            VRight v -> do-              runLogger-                $ logInfo $-                    "Stack " <> prettyVer (_tvVersion v) <> " successfully set as default version"-              pure ExitSuccess-            VLeft  e -> do-              runLogger $ logError $ T.pack $ prettyHFError e-              pure $ ExitFailure 14
lib-opt/GHCup/OptParse/Test.hs view
@@ -1,45 +1,44 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE TypeApplications  #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE TemplateHaskell   #-}-{-# LANGUAGE QuasiQuotes       #-}-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DuplicateRecordFields #-}-{-# LANGUAGE ViewPatterns      #-}-{-# LANGUAGE TypeOperators     #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}  module GHCup.OptParse.Test where    -import           GHCup.OptParse.Common+import GHCup.OptParse.Common -import           GHCup-import           GHCup.Errors-import           GHCup.Types-import           GHCup.Utils.Dirs-import           GHCup.Utils.Parsers (fromVersion, uriParser)-import           GHCup.Prelude-import           GHCup.Prelude.Logger-import           GHCup.Prelude.String.QQ+import GHCup.Command.Test.GHC+import GHCup.Errors+import GHCup.Input.Parsers     ( resolveVersion, uriParser )+import GHCup.Prelude+import GHCup.Prelude.String.QQ+import GHCup.Query.GHCupDirs+import GHCup.Query.Metadata+import GHCup.Types+import GHCup.Types.Optics  #if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )+import Control.Monad.Fail ( MonadFail ) #endif-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-import           Data.Functor-import           Data.Maybe-import           Data.Variant.Excepts-import           Options.Applicative     hiding ( style )-import           Options.Applicative.Pretty.Shim ( text )-import           Prelude                 hiding ( appendFile )-import           System.Exit-import           URI.ByteString          hiding ( uriParser )+import Control.Monad.Reader+import Control.Monad.Trans.Resource+import Data.Functor+import Data.Maybe+import Data.Variant.Excepts+import Options.Applicative             hiding ( ParseError, style )+import Options.Applicative.Pretty.Shim ( text )+import Prelude                         hiding ( appendFile )+import System.Exit+import URI.ByteString                  hiding ( uriParser ) -import qualified Data.Text                     as T+import qualified Data.Text as T   @@ -60,9 +59,9 @@   data TestOptions = TestOptions-  { testVer      :: Maybe ToolVersion-  , testBindist  :: Maybe URI-  , addMakeArgs  :: [T.Text]+  { testVer :: Maybe ToolVersion+  , testBindist :: Maybe URI+  , addMakeArgs :: [T.Text]   }  @@ -89,7 +88,7 @@           "ghc"           (   TestGHC           <$> info-                (testOpts (Just GHC) <**> helper)+                (testOpts (Just ghc) <**> helper)                 (  progDesc "Test GHC"                 <> footerDoc (Just $ text testGHCFooter)                 )@@ -110,7 +109,7 @@                     (eitherReader uriParser)                     (short 'u' <> long "url" <> metavar "BINDIST_URL" <> help                       "Install the specified version from this bindist"-                      <> completer (toolDlCompleter (fromMaybe GHC tool))+                      <> completer (toolDlCompleter (fromMaybe ghc tool))                     )                   )             <*> (Just <$> toolVersionTagArgument [] tool)@@ -144,16 +143,10 @@                       , DayNotFound                       , NoToolVersionSet                       , URIParseError+                      , NoInstallInfo+                      , ParseError                       ] -runTestGHC :: AppState-           -> Excepts TestGHCEffects (ResourceT (ReaderT AppState IO)) a-           -> IO (VEither TestGHCEffects a)-runTestGHC appstate' =-  flip runReaderT appstate'-  . runResourceT-  . runE-    @TestGHCEffects       -------------------@@ -161,29 +154,39 @@     -------------------  -test :: TestCommand -> Settings -> IO AppState -> (ReaderT LeanAppState IO () -> IO ()) -> IO ExitCode-test testCommand settings getAppState' runLogger = case testCommand of+test :: TestCommand -> Settings -> (IO (AppState, IO ()), LeanAppState) -> IO ExitCode+test testCommand settings (getAppState', leanAppstate) = case testCommand of   (TestGHC iopts) -> go iopts  where   guessMode = if guessVersion settings then GLaxWithInstalled else GStrict+  runLogger = flip runReaderT leanAppstate    go :: TestOptions -> IO ExitCode   go TestOptions{..} = do-    s'@AppState{ dirs = Dirs{ .. } } <- liftIO getAppState'+    (s'@AppState{ dirs = Dirs{ .. } }, up) <- getAppState'+    let run appstate' = flip runReaderT (appstate' :: AppState)+            . runResourceT+            . runE+            @TestGHCEffects     (case testBindist of-       Nothing -> runTestGHC s' $ do-         (v, vi) <- liftE $ fromVersion testVer guessMode GHC-         liftE $ testGHCVer v addMakeArgs-         pure vi+       Nothing -> run s' $ do+         GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo+         treq@(TargetVersionReq tver _) <- liftE $ resolveVersion testVer guessMode ghc+         let vm = getVersionMetadata tver ghcup dls+         liftE $ testGHCVer treq addMakeArgs+         pure vm        Just uri -> do-         runTestGHC s'{ settings = settings {noVerify = True}} $ do-           (v, vi) <- liftE $ fromVersion testVer guessMode GHC-           liftE $ testGHCBindist (DownloadInfo ((decUTF8Safe . serializeURIRef') uri) (Just $ RegexDir ".*/.*") "" Nothing Nothing Nothing) v addMakeArgs-           pure vi+         run s'{ settings = settings {noVerify = True}} $ do+           GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo+           (TargetVersionReq tver _) <- liftE $ resolveVersion testVer guessMode ghc+           let vm = getVersionMetadata tver ghcup dls+           liftE $ testGHCBindist (DownloadInfo ((decUTF8Safe . serializeURIRef') uri) (Just $ RegexDir ".*/.*") "" Nothing Nothing Nothing Nothing) tver addMakeArgs+           pure vm       )         >>= \case               VRight _ -> do                 runLogger $ logInfo "GHC test successful"+                liftIO up                 pure ExitSuccess               VLeft e -> do                 runLogger $ do
lib-opt/GHCup/OptParse/ToolRequirements.hs view
@@ -28,9 +28,9 @@ import qualified Data.Text.IO                  as T import Control.Exception.Safe (MonadMask) import GHCup.Types.Optics-import GHCup.Platform+import GHCup.Query.System import GHCup.Prelude-import GHCup.Requirements+import GHCup.Query.Metadata import System.IO  @@ -51,7 +51,7 @@     --[ Parsers ]--     --------------- -          + toolReqP :: Parser ToolReqOpts toolReqP =   ToolReqOpts@@ -103,13 +103,13 @@                     , Alternative m                     )                  => ToolReqOpts-                 -> (ReaderT AppState m (VEither ToolRequirementsEffects ()) -> m (VEither ToolRequirementsEffects ()))-                 -> (ReaderT LeanAppState m () -> m ())+                 -> (IO (AppState, IO ()), LeanAppState)                  -> m ExitCode-toolRequirements ToolReqOpts{..} runAppState runLogger = runToolRequirements runAppState (do+toolRequirements ToolReqOpts{..} (getAppState', leanAppstate) = run (do     GHCupInfo { .. } <- lift getGHCupInfo     platform' <- liftE getPlatform-    req       <- getCommonRequirements platform' _toolRequirements ?? NoToolRequirements+    -- TODO+    req       <- getCommonRequirements ghc platform' _toolRequirements ?? NoToolRequirements     if tlrRaw     then liftIO $ T.hPutStr stdout (rawRequirements req)     else liftIO $ T.hPutStr stdout (prettyRequirements req)@@ -119,3 +119,12 @@           VLeft  e -> do             runLogger $ logError $ T.pack $ prettyHFError e             pure $ ExitFailure 12+ where+  run action' = do+    (appstate', _) <- liftIO getAppState'+    flip runReaderT appstate'+                  . runResourceT+                  . runE+                    @ToolRequirementsEffects+                  $ action'+  runLogger = flip runReaderT leanAppstate
lib-opt/GHCup/OptParse/UnSet.hs view
@@ -2,7 +2,6 @@ {-# LANGUAGE DataKinds         #-} {-# LANGUAGE TypeApplications  #-} {-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE TemplateHaskell   #-} {-# LANGUAGE QuasiQuotes       #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE DuplicateRecordFields #-}@@ -13,8 +12,9 @@   -import           GHCup import           GHCup.Errors+import           GHCup.Input.Parsers (toolParser)+import           GHCup.Command.Set import           GHCup.Types import           GHCup.Prelude.Logger import           GHCup.Prelude.String.QQ@@ -27,18 +27,19 @@ import           Data.Functor import           Data.Maybe import           Data.Variant.Excepts-import           Options.Applicative     hiding ( style )+import           Options.Applicative     hiding ( style, ParseError ) import           Options.Applicative.Pretty.Shim ( text ) import           Prelude                 hiding ( appendFile ) import           System.Exit  import qualified Data.Text                     as T-import Control.Exception.Safe (MonadMask)-import GHCup.Types.Optics+import           Control.Exception.Safe (MonadMask) +import           Text.PrettyPrint.HughesPJClass (prettyShow)   +     ----------------     --[ Commands ]--     ----------------@@ -48,6 +49,7 @@                   | UnsetCabal UnsetOptions                   | UnsetHLS   UnsetOptions                   | UnsetStack UnsetOptions+                  | UnsetOther UnsetOptionsNew                   deriving (Eq, Show)  @@ -59,9 +61,13 @@   data UnsetOptions = UnsetOptions-  { sToolVer :: Maybe T.Text -- target platform triple+  { sToolTriple :: Maybe T.Text -- target platform triple   } deriving (Eq, Show) +data UnsetOptionsNew = UnsetOptionsNew+  { sTool :: Tool+  , sToolTriple :: Maybe T.Text -- target platform triple+  } deriving (Eq, Show)   @@ -109,6 +115,8 @@                  <> footerDoc (Just $ text unsetStackFooter)                  )            )+      ) <|>+      ( UnsetOther <$> unsetOptsNew       )  where   unsetGHCFooter :: String@@ -117,7 +125,7 @@     be a ~/.ghcup/bin/ghc anymore.  Examples:-  # unset ghc +  # unset ghc   ghcup unset ghc    # unset ghc for the target version@@ -139,8 +147,13 @@ unsetOpts :: Parser UnsetOptions unsetOpts = UnsetOptions . fmap T.pack <$> optional (argument str (metavar "TRIPLE")) +unsetOptsNew :: Parser UnsetOptionsNew+unsetOptsNew = UnsetOptionsNew+  <$> argument (eitherReader toolParser) (metavar "TOOL")+  <*> (fmap T.pack <$> optional (argument str (metavar "TRIPLE")))  +     --------------     --[ Footer ]--     --------------@@ -158,19 +171,11 @@     ---------------------------  -type UnsetEffects = '[ NotInstalled ]+type UnsetEffects = '[ NotInstalled, ParseError, NoToolVersionSet ]  -runUnsetGHC :: (ReaderT env m (VEither UnsetEffects a) -> m (VEither UnsetEffects a))-            -> Excepts UnsetEffects (ReaderT env m) a-            -> m (VEither UnsetEffects a)-runUnsetGHC runLeanAppState =-    runLeanAppState-    . runE-      @UnsetEffects  -     ------------------     --[ Entrypoint ]--     ------------------@@ -181,32 +186,30 @@          , MonadMask m          , MonadUnliftIO m          , MonadFail m-         , HasDirs env-         , HasLog env          )       => UnsetCommand-      -> (ReaderT env m (VEither UnsetEffects ())-          -> m (VEither UnsetEffects ()))-      -> (ReaderT LeanAppState m () -> m ())+      -> (IO (AppState, IO ()), LeanAppState)       -> m ExitCode-unset unsetCommand runLeanAppState runLogger = case unsetCommand of-  (UnsetGHC (UnsetOptions triple)) -> runUnsetGHC runLeanAppState (unsetGHC triple)+unset unsetCommand (_getAppState', leanAppstate) = case unsetCommand of+  (UnsetGHC usopts)   -> unsetOther (toUnsetOptionsNew ghc usopts)+  (UnsetCabal usopts) -> unsetOther (toUnsetOptionsNew cabal usopts)+  (UnsetHLS usopts)   -> unsetOther (toUnsetOptionsNew hls usopts)+  (UnsetStack usopts) -> unsetOther (toUnsetOptionsNew stack usopts)+  (UnsetOther usopts) -> unsetOther usopts++ where+  runLogger = flip runReaderT leanAppstate++  toUnsetOptionsNew sTool UnsetOptions{..} = UnsetOptionsNew{..}++  unsetOther UnsetOptionsNew{..} =+    (flip runReaderT leanAppstate . runE @UnsetEffects) (liftE $ unsetTool sTool sToolTriple)         >>= \case               VRight _ -> do-                runLogger $ logInfo "GHC successfully unset"+                runLogger $ logInfo $ T.pack (prettyShow sTool) <> " successfully unset"                 pure ExitSuccess               VLeft  e -> do                 runLogger $ logError $ T.pack $ prettyHFError e                 pure $ ExitFailure 14-  (UnsetCabal (UnsetOptions _)) -> do-    void $ runLeanAppState (VRight <$> unsetCabal)-    runLogger $ logInfo "Cabal successfully unset"-    pure ExitSuccess-  (UnsetHLS (UnsetOptions _)) -> do-    void $ runLeanAppState (VRight <$> unsetHLS)-    runLogger $ logInfo "HLS successfully unset"-    pure ExitSuccess-  (UnsetStack (UnsetOptions _)) -> do-    void $ runLeanAppState (VRight <$> unsetStack)-    runLogger $ logInfo "Stack successfully unset"-    pure ExitSuccess++
lib-opt/GHCup/OptParse/Upgrade.hs view
@@ -1,58 +1,59 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE TypeApplications  #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-}  module GHCup.OptParse.Upgrade where    -import           GHCup-import           GHCup.Errors-import           GHCup.Types-import           GHCup.Prelude.File-import           GHCup.Prelude.Logger+import GHCup.Command.Upgrade+import GHCup.Errors+import GHCup.Prelude.File+import GHCup.Prelude.Logger+import GHCup.Query.Metadata+import GHCup.Types+import GHCup.Types.Optics -import           Control.Concurrent (threadDelay)+import Control.Concurrent ( threadDelay ) #if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )+import Control.Monad.Fail ( MonadFail ) #endif-import           Control.Monad (forM_)-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-import           Data.Functor-import           Data.Maybe-import           Data.Variant.Excepts-import           Options.Applicative     hiding ( style )-import           Prelude                 hiding ( appendFile )-import           System.Exit--import qualified Data.Text                     as T-import Control.Exception.Safe (MonadMask)+import Control.Exception.Safe       ( MonadMask )+import Control.Monad                ( forM_ )+import Control.Monad.Reader+import Control.Monad.Trans.Resource+import Data.Functor+import Data.Maybe+import Data.Variant.Excepts+import Data.Versions+import Options.Applicative          hiding ( style )+import Prelude                      hiding ( appendFile ) import System.Environment-import GHCup.Utils+import System.Exit import System.FilePath-import GHCup.Types.Optics-import Data.Versions +import qualified Data.Text as T     +     ---------------     --[ Options ]--     ---------------  -data UpgradeOpts = UpgradeInplace-                 | UpgradeAt FilePath-                 | UpgradeGHCupDir-                 deriving (Eq, Show)+data UpgradeOpts+  = UpgradeInplace+  | UpgradeAt FilePath+  | UpgradeGHCupDir+  deriving (Eq, Show)   @@ -101,18 +102,8 @@                        ]  -runUpgrade :: MonadUnliftIO m-           => (ReaderT AppState m (VEither UpgradeEffects a) -> m (VEither UpgradeEffects a))-           -> Excepts UpgradeEffects (ResourceT (ReaderT AppState m)) a-           -> m (VEither UpgradeEffects a)-runUpgrade runAppState =-  runAppState-  . runResourceT-  . runE-    @UpgradeEffects  -     ------------------     --[ Entrypoint ]--     ------------------@@ -128,38 +119,48 @@         -> Bool         -> Bool         -> Dirs-        -> (forall a. ReaderT AppState m (VEither UpgradeEffects a) -> m (VEither UpgradeEffects a))-        -> (ReaderT LeanAppState m () -> m ())+        -> (IO (AppState, IO ()), LeanAppState)         -> m ExitCode-upgrade uOpts force' fatal Dirs{..} runAppState runLogger = do+upgrade uOpts force' fatal Dirs{..} (getAppState', leanAppstate) = do   target <- case uOpts of     UpgradeInplace  -> Just <$> liftIO getExecutablePath     (UpgradeAt p)   -> pure $ Just p     UpgradeGHCupDir -> pure (Just (binDir </> "ghcup" <> exeExt)) -  runUpgrade runAppState (do+  run (do     GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-    Just (tver, vi) <- pure $ getLatest dls GHCup+    Just tver <- pure $ getLatest dls ghcup     let latestVer = _tvVersion tver-    forM_ (_viPreInstall vi) $ \msg -> do+    let vm = getVersionMetadata tver ghcup dls+    forM_ (_vmPreInstall =<< vm) $ \msg -> do       lift $ logWarn msg       lift $ logWarn         "...waiting for 5 seconds, you can still abort..."       liftIO $ threadDelay 5000000 -- give the user a sec to intervene     v' <- liftE $ upgradeGHCup' target force' fatal latestVer-    pure (v', dls)+    pure (v', vm)     ) >>= \case-      VRight (v', dls) -> do+      (VRight (v', vm), up) -> do         let pretty_v = prettyVer v'-        let vi = fromJust $ snd <$> getLatest dls GHCup         runLogger $ logInfo $           "Successfully upgraded GHCup to version " <> pretty_v-        forM_ (_viPostInstall vi) $ \msg ->+        forM_ (_vmPostInstall =<< vm) $ \msg ->           runLogger $ logInfo msg+        liftIO up         pure ExitSuccess-      VLeft (V NoUpdate) -> do+      (VLeft (V NoUpdate), _) -> do         runLogger $ logWarn "No GHCup update available"         pure ExitSuccess-      VLeft e -> do+      (VLeft e, _) -> do         runLogger $ logError $ T.pack $ prettyHFError e         pure $ ExitFailure 11+ where+  runLogger = flip runReaderT leanAppstate+  run action' = do+    (appstate', up) <- liftIO getAppState'+    r <- flip runReaderT appstate'+                  . runResourceT+                  . runE+                    @UpgradeEffects+                  $ action'+    pure (r, up)
lib-opt/GHCup/OptParse/Whereis.hs view
@@ -1,45 +1,45 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE TypeApplications  #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell   #-}-{-# LANGUAGE QuasiQuotes       #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-}  module GHCup.OptParse.Whereis where    -import           GHCup-import           GHCup.Errors-import           GHCup.OptParse.Common-import           GHCup.Types-import           GHCup.Utils-import           GHCup.Utils.Parsers (fromVersion)-import           GHCup.Prelude.Logger-import           GHCup.Prelude.String.QQ+import GHCup.Command.Whereis+import GHCup.Errors+import GHCup.Input.Parsers     ( resolveVersion, toolParser )+import GHCup.OptParse.Common+import GHCup.Prelude.Logger+import GHCup.Prelude.String.QQ+import GHCup.Types  #if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )+import Control.Monad.Fail ( MonadFail ) #endif-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-import           Data.Functor-import           Data.Maybe-import           Data.Variant.Excepts-import           Options.Applicative     hiding ( style )-import           Options.Applicative.Pretty.Shim ( text )-import           Prelude                 hiding ( appendFile )-import           System.Environment-import           System.Exit+import Control.Monad.Reader+import Control.Monad.Trans.Resource+import Data.Functor+import Data.Maybe+import Data.Variant.Excepts+import Options.Applicative             hiding ( ParseError, style )+import Options.Applicative.Pretty.Shim ( text )+import Prelude                         hiding ( appendFile )+import System.Environment+import System.Exit+import System.FilePath -import qualified Data.Text                     as T-import Control.Exception.Safe (MonadMask)-import System.FilePath (takeDirectory)-import GHCup.Types.Optics+import           Control.Exception.Safe ( MonadMask )+import qualified Data.Text              as T+import           GHCup.Query.GHCupDirs+import           GHCup.System.Directory+import           GHCup.Types.Optics   @@ -49,13 +49,14 @@     ----------------  -data WhereisCommand = WhereisTool Tool (Maybe ToolVersion)-                    | WhereisBaseDir-                    | WhereisBinDir-                    | WhereisCacheDir-                    | WhereisLogsDir-                    | WhereisConfDir-                    deriving (Eq, Show)+data WhereisCommand+  = WhereisTool Tool (Maybe ToolVersion)+  | WhereisBaseDir+  | WhereisBinDir+  | WhereisCacheDir+  | WhereisLogsDir+  | WhereisConfDir+  deriving (Eq, Show)   @@ -66,9 +67,10 @@     ---------------  -data WhereisOptions = WhereisOptions {-   directory :: Bool-} deriving (Eq, Show)+data WhereisOptions = WhereisOptions+  { directory :: Bool+  }+  deriving (Eq, Show)   @@ -83,40 +85,41 @@   (commandGroup "Tools locations:" <>     command       "ghc"-      (WhereisTool GHC <$> info-        ( optional (toolVersionTagArgument [] (Just GHC)) <**> helper )+      (WhereisTool ghc <$> info+        ( optional (toolVersionTagArgument [] (Just ghc)) <**> helper )         ( progDesc "Get GHC location"         <> footerDoc (Just $ text whereisGHCFooter ))       )       <>      command       "cabal"-      (WhereisTool Cabal <$> info-        ( optional (toolVersionTagArgument [] (Just Cabal)) <**> helper )+      (WhereisTool cabal <$> info+        ( optional (toolVersionTagArgument [] (Just cabal)) <**> helper )         ( progDesc "Get cabal location"         <> footerDoc (Just $ text whereisCabalFooter ))       )       <>      command       "hls"-      (WhereisTool HLS <$> info-        ( optional (toolVersionTagArgument [] (Just HLS)) <**> helper )+      (WhereisTool hls <$> info+        ( optional (toolVersionTagArgument [] (Just hls)) <**> helper )         ( progDesc "Get HLS location"         <> footerDoc (Just $ text whereisHLSFooter ))       )       <>      command       "stack"-      (WhereisTool Stack <$> info-        ( optional (toolVersionTagArgument [] (Just Stack)) <**> helper )+      (WhereisTool stack <$> info+        ( optional (toolVersionTagArgument [] (Just stack)) <**> helper )         ( progDesc "Get stack location"         <> footerDoc (Just $ text whereisStackFooter ))       )       <>      command       "ghcup"-      (WhereisTool GHCup <$> info ( pure Nothing <**> helper ) ( progDesc "Get ghcup location" ))-    ) <|> subparser ( commandGroup "Directory locations:"+      (WhereisTool ghcup <$> info ( pure Nothing <**> helper ) ( progDesc "Get ghcup location" ))+    )+    <|> subparser ( commandGroup "Directory locations:"       <>      command       "basedir"@@ -148,6 +151,11 @@             ( progDesc "Get ghcup config directory location" )       )   )+    <|>+    (+     WhereisTool <$> argument (eitherReader toolParser) (metavar "TOOL")+                 <*> optional (toolVersionTagArgument [] Nothing)+    )  where   whereisGHCFooter = [s|Discussion:   Finds the location of a GHC executable, which usually resides in@@ -225,32 +233,13 @@                 , NextVerNotFound                 , TagNotFound                 , DayNotFound+                , ParseError+                , NoInstallInfo                 ]  -runLeanWhereIs :: (MonadUnliftIO m, MonadIO m)-               => LeanAppState-               -> Excepts WhereisEffects (ReaderT LeanAppState m) a-               -> m (VEither WhereisEffects a)-runLeanWhereIs leanAppstate =-    -- Don't use runLeanAppState here, which is disabled on windows.-    -- This is the only command on all platforms that doesn't need full appstate.-    flip runReaderT leanAppstate-    . runE-      @WhereisEffects  -runWhereIs :: (MonadUnliftIO m, MonadIO m)-           => (ReaderT AppState m (VEither WhereisEffects a) -> m (VEither WhereisEffects a))-           -> Excepts WhereisEffects (ReaderT AppState m) a-           -> m (VEither WhereisEffects a)-runWhereIs runAppState =-    runAppState-    . runE-      @WhereisEffects---     ------------------     --[ Entrypoint ]--     ------------------@@ -265,26 +254,24 @@       => WhereisCommand       -> WhereisOptions       -> Settings-      -> (forall a. ReaderT AppState m (VEither WhereisEffects a) -> m (VEither WhereisEffects a))-      -> LeanAppState-      -> (ReaderT LeanAppState m () -> m ())+      -> (IO (AppState, IO ()), LeanAppState)       -> m ExitCode-whereis whereisCommand whereisOptions settings runAppState leanAppstate runLogger = do+whereis whereisCommand whereisOptions settings (getAppState', leanAppstate) = do   Dirs{ .. }  <- runReaderT getDirs leanAppstate   case (whereisCommand, whereisOptions) of-    (WhereisTool GHCup _, WhereisOptions{..}) -> do-      loc <- liftIO (getExecutablePath >>= canonicalizePath )+    (WhereisTool (Tool "ghcup") _, WhereisOptions{..}) -> do+      loc <- liftIO (getExecutablePath >>= canon )       if directory       then liftIO $ putStr $ takeDirectory loc       else liftIO $ putStr loc       pure ExitSuccess -    (WhereisTool tool (Just (GHCVersion v)), WhereisOptions{..}) ->-      runLeanWhereIs leanAppstate (do+    (WhereisTool tool (Just (GHCVersion (TargetVersionReq v _))), WhereisOptions{..}) ->+      runLeanWhereIs (do         loc <- liftE $ whereIsTool tool v         if directory-        then pure $ takeDirectory loc-        else pure loc+        then takeDirectory <$> canon loc+        else canon loc         )         >>= \case               VRight r -> do@@ -293,12 +280,12 @@               VLeft e -> do                 runLogger $ logError $ T.pack $ prettyHFError e                 pure $ ExitFailure 30-    (WhereisTool tool (Just (ToolVersion v)), WhereisOptions{..}) ->-      runLeanWhereIs leanAppstate (do+    (WhereisTool tool (Just (ToolVersion (VersionReq v _))), WhereisOptions{..}) ->+      runLeanWhereIs (do         loc <- liftE $ whereIsTool tool (mkTVer v)         if directory-        then pure $ takeDirectory loc-        else pure loc+        then takeDirectory <$> canon loc+        else canon loc         )         >>= \case               VRight r -> do@@ -309,12 +296,12 @@                 pure $ ExitFailure 30      (WhereisTool tool whereVer, WhereisOptions{..}) -> do-      runWhereIs runAppState (do-        (v, _) <- liftE $ fromVersion whereVer guessMode tool+      runWhereIs (do+        (TargetVersionReq v _) <- liftE $ resolveVersion whereVer guessMode tool         loc <- liftE $ whereIsTool tool v         if directory-        then pure $ takeDirectory loc-        else pure loc+        then takeDirectory <$> canon loc+        else canon loc         )         >>= \case               VRight r -> do@@ -325,23 +312,44 @@                 pure $ ExitFailure 30      (WhereisBaseDir, _) -> do-      liftIO $ putStr $ fromGHCupPath baseDir+      liftIO $ putStr =<< canon (fromGHCupPath baseDir)       pure ExitSuccess      (WhereisBinDir, _) -> do-      liftIO $ putStr binDir+      liftIO $ putStr =<< canon binDir       pure ExitSuccess      (WhereisCacheDir, _) -> do-      liftIO $ putStr $ fromGHCupPath cacheDir+      liftIO $ putStr =<< canon (fromGHCupPath cacheDir)       pure ExitSuccess      (WhereisLogsDir, _) -> do-      liftIO $ putStr $ fromGHCupPath logsDir+      liftIO $ putStr =<< canon (fromGHCupPath logsDir)       pure ExitSuccess      (WhereisConfDir, _) -> do-      liftIO $ putStr $ fromGHCupPath confDir+      liftIO $ putStr =<< canon (fromGHCupPath confDir)       pure ExitSuccess  where+  runLogger = flip runReaderT leanAppstate++  -- make sure we only have forward slashes on windows+  canon fp = do+    cfp <- liftIO $ canonicalizePath fp+    pure $ map (\c -> if isPathSeparator c then '/' else c) cfp+   guessMode = if guessVersion settings then GLaxWithInstalled else GStrict+  runLeanWhereIs =+      -- Don't use runLeanAppState here, which is disabled on windows.+      -- This is the only command on all platforms that doesn't need full appstate.+      flip runReaderT leanAppstate+      . runE+        @WhereisEffects++  runWhereIs action' = do+    (appstate', _) <- liftIO getAppState'+    flip runReaderT appstate'+                  . runResourceT+                  . runE+                    @WhereisEffects+                  $ action'
lib-tui/GHCup/Brick/Actions.hs view
@@ -1,88 +1,97 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE FlexibleContexts  #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TypeApplications  #-}-{-# LANGUAGE RankNTypes        #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-} {-# OPTIONS_GHC -Wno-unused-record-wildcards #-} {-# OPTIONS_GHC -Wno-unused-matches #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ViewPatterns #-}  module GHCup.Brick.Actions where -import           GHCup-import           GHCup.CabalConfig-import           GHCup.Download-import           GHCup.Errors-import           GHCup.Types.Optics ( getDirs, getPlatformReq, HasLog )-import           GHCup.Types         hiding ( LeanAppState(..) )-import           GHCup.Utils-import           GHCup.Prelude ( decUTF8Safe, runBothE' )-import           GHCup.Prelude.Logger-import           GHCup.Prelude.Process-import           GHCup.Prompts-import           GHCup.Brick.Common (BrickData(..), BrickSettings(..), Name(..), Mode(..))-import qualified GHCup.Brick.Common as Common-import           GHCup.Brick.BrickState-import           GHCup.Brick.Widgets.SectionList-import qualified GHCup.Brick.Widgets.Menus.Context as ContextMenu-import           GHCup.Brick.Widgets.Navigation (BrickInternalState)-import qualified GHCup.Brick.Widgets.Menus.AdvanceInstall as AdvanceInstall-import qualified GHCup.Brick.Widgets.Menus.CompileGHC as CompileGHC-import           GHCup.Brick.Widgets.Menu (MenuKeyBindings(..))+import GHCup.CabalConfig+import GHCup.Command.Install+import GHCup.Command.List+import GHCup.Command.Rm+import GHCup.Command.Set+import GHCup.Command.Upgrade+import GHCup.Download+import GHCup.Errors+import GHCup.Input.Prompts+import GHCup.Prelude+import GHCup.Prelude.Process+import GHCup.Query.GHCupDirs+import GHCup.Query.Metadata+import GHCup.System.Directory+import GHCup.Types            hiding ( LeanAppState (..) )+import GHCup.Types.Optics     ( HasLog, getDirs, getPlatformReq ) +import qualified GHCup.Command.Compile.GHC as GHC+import qualified GHCup.Command.Compile.HLS as HLS+import qualified GHCup.Input.Parsers       as Utils++import GHCup.Brick.BrickState+import GHCup.Brick.Common+    ( BrickData (..), BrickSettings (..), Mode (..), Name (..) )+import GHCup.Brick.Widgets.Menu        ( MenuKeyBindings (..) )+import GHCup.Brick.Widgets.Navigation  ( BrickInternalState )++import qualified GHCup.Brick.Common                        as Common+import qualified GHCup.Brick.Widgets.Menus.AdvancedInstall as AdvancedInstall+import qualified GHCup.Brick.Widgets.Menus.CompileGHC      as CompileGHC+import qualified GHCup.Brick.Widgets.Menus.CompileHLS      as CompileHLS+import qualified GHCup.Brick.Widgets.Menus.Context         as ContextMenu+ import qualified Brick-import qualified Brick.Widgets.List as L-import qualified Brick.Focus as F+import qualified Brick.Widgets.List     as L import           Control.Applicative import           Control.Exception.Safe-import           Control.Monad (when, forM, forM_)+import           Control.Monad          ( forM, forM_, when ) #if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )+import Control.Monad.Fail ( MonadFail ) #endif-import           Control.Monad.Reader-import           Control.Monad.Trans.Except-import           Control.Monad.Trans.Resource-import           Data.Bool-import           Data.Functor-import           Data.Function ( (&), on)-import           Data.List-import           Data.Maybe-import           Data.IORef (IORef, readIORef, newIORef, modifyIORef)-import           Data.Versions hiding (Lens')-import           Data.Variant.Excepts-import           Prelude                 hiding ( appendFile )-import           System.Exit-import           System.IO.Unsafe-import           System.Process                 ( system )-import           Text.PrettyPrint.HughesPJClass ( prettyShow )-import           URI.ByteString+import Control.Monad.Reader+import Control.Monad.Trans.Except+import Control.Monad.Trans.Resource+import Data.Bool+import Data.Function                  ( (&) )+import Data.Functor+import qualified Data.Map.Strict as M+import Data.IORef+    ( IORef, modifyIORef, newIORef, readIORef )+import Data.List+import Data.Maybe+import Data.Variant.Excepts+import Data.Versions                  hiding ( Lens' )+import Prelude                        hiding ( appendFile )+import System.Exit+import System.IO.Unsafe+import System.Process                 ( system )+import Text.PrettyPrint.HughesPJClass ( prettyShow )+import URI.ByteString -import qualified Data.Text                     as T-import qualified Data.Text.Lazy.Builder        as B-import qualified Data.Text.Lazy                as L-import qualified Graphics.Vty                  as Vty-import qualified Data.Vector                   as V-import System.Environment (getExecutablePath)+import qualified Data.Text              as T+import qualified Data.Text.Lazy         as L+import qualified Data.Text.Lazy.Builder as B+import qualified Data.Vector            as V+import qualified Graphics.Vty           as Vty+import           System.Environment     ( getExecutablePath ) #if !IS_WINDOWS-import           GHCup.Prelude.File-import qualified System.Posix.Process          as SPP+import qualified System.Posix.Process as SPP #endif -import           System.FilePath+import System.FilePath -import           Optics.State (use)-import           Optics.State.Operators ( (.=))-import           Optics.Operators ((.~),(%~))-import           Optics.Getter (view)-import Optics.Optic ((%))-import Optics ((^.), to)-import qualified GHCup.Brick.Widgets.Menus.CompileHLS as CompileHLS-import Control.Concurrent (threadDelay)-import qualified GHCup.GHC as GHC-import qualified GHCup.Utils.Parsers as Utils-import qualified GHCup.HLS as HLS+import Control.Concurrent     ( threadDelay )+import Optics                 ( to, (^.) )+import Optics.Getter          ( view )+import Optics.Operators       ( (.~) )+import Optics.Optic           ( (%) )+import Optics.State           ( use )+import Optics.State.Operators ( (.=), (%=) )   @@ -118,37 +127,41 @@ -- | Focus on the tool section and the predicate which matches. If no result matches, focus on index 0 selectBy :: Tool -> (ListResult -> Bool) -> BrickInternalState -> BrickInternalState selectBy tool predicate internal_state =-  let new_focus = F.focusSetCurrent (Singular tool) (view sectionListFocusRingL internal_state)-      tool_lens = sectionL (Singular tool)-   in internal_state-        & sectionListFocusRingL .~ new_focus-        & tool_lens %~ L.listMoveTo 0            -- We move to 0 first-        & tool_lens %~ L.listFindBy predicate    -- The lookup by the predicate.+  L.listModify+    (\(t, (td, vlr)) -> (t, (td, maybe vlr (`L.listMoveToElement` vlr) . V.find predicate $ L.listElements vlr)))+    (L.listFindBy (\(t, _) -> tool == t) internal_state) --- | Select the latests GHC tool+-- | Select the latest GHC tool selectLatest :: BrickInternalState -> BrickInternalState-selectLatest = selectBy GHC (elem Latest . lTag)-+selectLatest = selectBy ghc (elem Latest . lTag)  -- | Replace the @appState@ or construct it based on a filter function -- and a new @[ListResult]@ evidence. -- When passed an existing @appState@, tries to keep the selected element. replaceLR :: (ListResult -> Bool)-          -> [ListResult]+          -> ToolListResult           -> Maybe BrickInternalState           -> BrickInternalState replaceLR filterF list_result s =-  let oldElem = s >>= sectionListSelectedElement -- Maybe (Int, e)-      newVec  =  [(Singular $ lTool (head g), V.fromList g) | g <- groupBy ((==) `on` lTool ) (filter filterF list_result)]-      newSectionList = sectionList AllTools newVec 1+  let oldElem = s >>= L.listSelectedElement -- Maybe (Int, e)   in case oldElem of-      Just (_, el) -> selectBy (lTool el) (toolEqual el) newSectionList-      Nothing -> selectLatest newSectionList+      Just (_, (tool, (toolDesc, elr))) -> do+        case L.listSelectedElement elr of+          Just (_, lr) ->+            selectBy tool (\lr' -> lVer lr == lVer lr' && lCross lr == lCross lr') newList+          Nothing -> selectBy tool (elem Latest . lTag) newList+      Nothing ->+        let bis' = foldl' (\bis tool -> selectBy tool (elem Latest . lTag) bis) newList (M.keys list_result)+        in L.listFindBy (\(t, _) -> ghc == t) bis'  where-  toolEqual e1 e2 =-    lTool e1 == lTool e2 && lVer e1 == lVer e2 && lCross e1 == lCross e2+   newList :: BrickInternalState+   newList =+      L.list+        AllTools+        (V.fromList $ fmap (\(tool, (td, filter filterF -> lr)) -> (tool, (td, L.list (Singular tool) (V.fromList lr) 1))) $ M.toList list_result) 1  + filterVisible :: Bool -> ListResult -> Bool filterVisible v e | lInstalled e = True                   | v@@ -157,45 +170,70 @@                   , Old `notElem` lTag e                   , Nightly `notElem` lTag e = True                   | otherwise = (Old `notElem` lTag e)       &&-                                  (Nightly `notElem` lTag e)+                                (Nightly `notElem` lTag e)  -- | Suspend the current UI and run an IO action in terminal. If the -- IO action returns a Left value, then it's thrown as userError. withIOAction :: (Ord n, Eq n)-             => ( (Int, ListResult) -> ReaderT AppState IO (Either String a))+             => ( (Int, Tool, Maybe ToolDescription, ListResult) -> ReaderT AppState IO (Either String a))              -> Brick.EventM n BrickState () withIOAction action = do   as <- Brick.get-  case sectionListSelectedElement (view appState as) of+  case L.listSelectedElement (view appState as) of     Nothing      -> pure ()-    Just (curr_ix, e) -> do-      Brick.suspendAndResume $ do-        settings <- readIORef settings'-        flip runReaderT settings $ action (curr_ix, e) >>= \case-          Left  err -> liftIO $ putStrLn ("Error: " <> err)-          Right _   -> liftIO $ putStrLn "Success"-        getAppData Nothing >>= \case-          Right data' -> do-            putStrLn "Press enter to continue"-            _ <- getLine-            pure (updateList data' as)-          Left err -> throwIO $ userError err+    Just (curr_ix, (tool, (td, vlr))) -> case L.listSelectedElement vlr of+      Just (curr_ix', lr) ->+        Brick.suspendAndResume $ do+          settings <- readIORef settings'+          flip runReaderT settings $ action (curr_ix', tool, td, lr) >>= \case+            Left  err -> liftIO $ putStrLn ("Error: " <> err)+            Right _   -> liftIO $ putStrLn "Success"+          getAppData Nothing >>= \case+            Right data' -> do+              putStrLn "Press enter to continue"+              _ <- getLine+              pure (updateList data' as)+            Left err -> throwIO $ userError err+      Nothing      -> pure () -installWithOptions :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, MonadMask m, MonadUnliftIO m, Alternative m)-         => AdvanceInstall.InstallOptions-         -> (Int, ListResult)+withIOActionRecommended :: (Ord n, Eq n)+                        => ( (Int, Tool, Maybe ToolDescription, ListResult) -> ReaderT AppState IO (Either String a))+                        -> Brick.EventM n BrickState ()+withIOActionRecommended action = do+  as <- Brick.get+  case L.listSelectedElement (view appState as) of+    Nothing      -> pure ()+    Just (curr_ix, (tool, (td, vlr))) -> do+      let mlr = V.find (\ListResult{..} -> Recommended `elem` lTag) $ L.listElements vlr+      case mlr of+        Just lr ->+          Brick.suspendAndResume $ do+            settings <- readIORef settings'+            flip runReaderT settings $ action (curr_ix, tool, td, lr) >>= \case+              Left  err -> liftIO $ putStrLn ("Error: " <> err)+              Right _   -> liftIO $ putStrLn "Success"+            getAppData Nothing >>= \case+              Right data' -> do+                putStrLn "Press enter to continue"+                _ <- getLine+                pure (updateList data' as)+              Left err -> throwIO $ userError err+        Nothing -> pure ()++installWithOptions :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, MonadMask m, MonadUnliftIO m)+         => AdvancedInstall.InstallOptions+         -> (Int, Tool, Maybe ToolDescription, ListResult)          -> m (Either String ())-installWithOptions opts (_, ListResult {..}) = do+installWithOptions opts (_ix, lTool, td, ListResult {..}) = do   AppState { ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask   let-    misolated = opts ^. AdvanceInstall.isolateDirL-    shouldIsolate = maybe GHCupInternal IsolateDir (opts ^. AdvanceInstall.isolateDirL)-    shouldForce   = opts ^. AdvanceInstall.forceInstallL-    shouldSet     = opts ^. AdvanceInstall.instSetL-    extraArgs     = opts ^. AdvanceInstall.addConfArgsL-    installTargets = opts ^. AdvanceInstall.installTargetsL-    v = fromMaybe (GHCTargetVersion lCross lVer) (opts ^. AdvanceInstall.instVersionL)-    toolV = _tvVersion v+    misolated = opts ^. AdvancedInstall.isolateDirL+    shouldIsolate = maybe GHCupInternal IsolateDir (opts ^. AdvancedInstall.isolateDirL)+    shouldForce   = opts ^. AdvancedInstall.forceInstallL+    shouldSet     = opts ^. AdvancedInstall.instSetL+    extraArgs     = opts ^. AdvancedInstall.addConfArgsL+    installTargets = opts ^. AdvancedInstall.installTargetsL+    v = fromMaybe (TargetVersionReq (TargetVersion lCross lVer) (Just (fst lRev))) (opts ^. AdvancedInstall.instVersionL)   let run =         runResourceT           . runE@@ -227,6 +265,8 @@               , NoCompatibleArch               , InstallSetError               , URIParseError+              , NoInstallInfo+              , MalformedInstallInfo               ]        withNoVerify :: (MonadReader AppState m) => m a -> m a@@ -237,110 +277,52 @@         try @_ @SomeException $ getExecutablePath >>= canonicalizePath       dirs <- lift getDirs       case lTool of-        GHC   -> do-          let vi = getVersionInfo v GHC dls-          forM_ (_viPreInstall =<< vi) $ \msg -> do-            lift $ logWarn msg-            lift $ logWarn-              "...waiting for 5 seconds, you can still abort..."-            liftIO $ threadDelay 5000000 -- give the user a sec to intervene-          case opts ^. AdvanceInstall.instBindistL of-            Nothing -> do-              liftE $-                runBothE'-                  (installGHCBin v shouldIsolate shouldForce extraArgs installTargets)-                  (when (shouldSet && isNothing misolated) (liftE $ void $ setGHC v SetGHCOnly Nothing))-              pure (vi, dirs, ce)-            Just uri -> do-              liftE $-                runBothE'-                  (withNoVerify $ installGHCBindist-                      (DownloadInfo ((decUTF8Safe . serializeURIRef') uri) (Just $ RegexDir "ghc-.*") "" Nothing Nothing Nothing)-                      v-                      shouldIsolate-                      shouldForce-                      extraArgs-                      installTargets-                      )-                  (when (shouldSet && isNothing misolated) (liftE $ void $ setGHC v SetGHCOnly Nothing))-              pure (vi, dirs, ce)--        Cabal -> do-          let vi = getVersionInfo v Cabal dls-          forM_ (_viPreInstall =<< vi) $ \msg -> do-            lift $ logWarn msg-            lift $ logWarn-              "...waiting for 5 seconds, you can still abort..."-            liftIO $ threadDelay 5000000 -- give the user a sec to intervene-          case opts ^. AdvanceInstall.instBindistL of-            Nothing -> do-              liftE $-                runBothE'-                  (installCabalBin toolV shouldIsolate shouldForce)-                  (when (shouldSet && isNothing misolated) (liftE $ void $ setCabal toolV))-              pure (vi, dirs, ce)-            Just uri -> do-              liftE $-                runBothE'-                  (withNoVerify $ installCabalBindist (DownloadInfo ((decUTF8Safe . serializeURIRef') uri) Nothing "" Nothing Nothing Nothing) toolV shouldIsolate shouldForce)-                  (when (shouldSet && isNothing misolated) (liftE $ void $ setCabal toolV))-              pure (vi, dirs, ce)--        GHCup -> do-          let vi = snd <$> getLatest dls GHCup-          forM_ (_viPreInstall =<< vi) $ \msg -> do+        Tool "ghcup" -> do+          let vm = getLatest dls lTool >>= \t -> getVersionMetadata t lTool dls+          forM_ (_vmPreInstall =<< vm) $ \msg -> do             lift $ logWarn msg             lift $ logWarn               "...waiting for 5 seconds, you can still abort..."             liftIO $ threadDelay 5000000 -- give the user a sec to intervene-          liftE $ upgradeGHCup Nothing False False $> (vi, dirs, ce)-        HLS   -> do-          let vi = getVersionInfo v HLS dls-          forM_ (_viPreInstall =<< vi) $ \msg -> do+          liftE $ upgradeGHCup Nothing False False $> (vm, dirs, ce)+        _ -> do+          let vm = getLatest dls lTool >>= \t -> getVersionMetadata t lTool dls+          forM_ (_vmPreInstall =<< vm) $ \msg -> do             lift $ logWarn msg             lift $ logWarn               "...waiting for 5 seconds, you can still abort..."             liftIO $ threadDelay 5000000 -- give the user a sec to intervene-          case opts ^. AdvanceInstall.instBindistL of-            Nothing -> do-              liftE $-                runBothE'-                  (installHLSBin toolV shouldIsolate shouldForce)-                  (when (shouldSet && isNothing misolated) (liftE $ void $ setHLS toolV SetHLSOnly Nothing))-              pure (vi, dirs, ce)-            Just uri -> do-              liftE $-                runBothE'-                  (withNoVerify $ installHLSBindist-                    (DownloadInfo ((decUTF8Safe . serializeURIRef') uri) (if isWindows then Nothing else Just (RegexDir "haskell-language-server-*")) "" Nothing Nothing Nothing)-                    toolV-                    shouldIsolate-                    shouldForce)-                  (when (shouldSet && isNothing misolated)  (liftE $ void $ setHLS toolV SetHLSOnly Nothing))-              pure (vi, dirs, ce)--        Stack -> do-          let vi = getVersionInfo v Stack dls-          case opts ^. AdvanceInstall.instBindistL of+          case opts ^. AdvancedInstall.instBindistL of             Nothing -> do               liftE $                 runBothE'-                  (installStackBin toolV shouldIsolate shouldForce)-                  (when (shouldSet && isNothing misolated) (liftE $ void $ setStack toolV))-              pure (vi, dirs, ce)+                  (installTool lTool v shouldIsolate shouldForce (T.unpack <$> extraArgs) (words . T.unpack <$> installTargets))+                  (when (shouldSet && isNothing misolated) (liftE $ void $ setToolVersion lTool (_tvqTargetVer v)))+              pure (vm, dirs, ce)             Just uri -> do               liftE $                 runBothE'-                  (withNoVerify $ installStackBindist (DownloadInfo ((decUTF8Safe . serializeURIRef') uri) Nothing "" Nothing Nothing Nothing) toolV shouldIsolate shouldForce)-                  (when (shouldSet && isNothing misolated) (liftE $ void $ setStack toolV))-              pure (vi, dirs, ce)+                  (do+                    rev <- liftE $ maybe (fmap fst $ getDownloadInfoE' lTool v) pure (_tvqRev v)+                    withNoVerify $ installBindist+                      lTool+                      td+                      (DownloadInfo ((decUTF8Safe . serializeURIRef') uri) (Just $ RegexDir "ghc-.*") "" Nothing Nothing Nothing Nothing)+                      (TargetVersionRev (_tvqTargetVer v) rev)+                      shouldIsolate+                      shouldForce+                      (T.unpack <$> extraArgs)+                      (words . T.unpack <$> installTargets)+                  )+                  (when (shouldSet && isNothing misolated) (liftE $ void $ setToolVersion lTool (_tvqTargetVer v)))+              pure (vm, dirs, ce)      )     >>= \case-          VRight (vi, Dirs{..}, Just ce) -> do-            forM_ (_viPostInstall =<< vi) $ \msg -> logInfo msg+          VRight (vm, Dirs{..}, Just ce) -> do+            forM_ (_vmPostInstall =<< vm) $ \msg -> logInfo msg             case lTool of-              GHCup -> do+              Tool "ghcup" -> do #if !IS_WINDOWS                 up <- liftIO $ fmap (either (const Nothing) Just)                   $ try @_ @SomeException $ canonicalizePath (binDir </> "ghcup" <.> exeExt)@@ -352,23 +334,23 @@ #endif               _ -> pure ()             pure $ Right ()-          VRight (vi, _, _) -> do-            forM_ (_viPostInstall =<< vi) $ \msg -> logInfo msg+          VRight (vm, _, _) -> do+            forM_ (_vmPostInstall =<< vm) $ \msg -> logInfo msg             logInfo "Please restart 'ghcup' for the changes to take effect"             pure $ Right ()           VLeft  (V (AlreadyInstalled _ _)) -> pure $ Right ()           VLeft (V NoUpdate) -> pure $ Right ()           VLeft e -> pure $ Left $ prettyHFError e <> "\n"-            <> "Also check the logs in ~/.ghcup/logs"+            <> "Also check the logs in ~/.ghcup/logs or $XDG_STATE_HOME/ghcup/logs" -install' :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, MonadMask m, MonadUnliftIO m, Alternative m)-         => (Int, ListResult) -> m (Either String ())-install' = installWithOptions (AdvanceInstall.InstallOptions Nothing False Nothing Nothing False [] "install")+install' :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, MonadMask m, MonadUnliftIO m)+         => (Int, Tool, Maybe ToolDescription, ListResult) -> m (Either String ())+install' = installWithOptions (AdvancedInstall.InstallOptions Nothing False Nothing Nothing False [] Nothing) -set' :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, MonadMask m, MonadUnliftIO m, Alternative m)-     => (Int, ListResult)+set' :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, MonadMask m, MonadUnliftIO m)+     => (Int, Tool, Maybe ToolDescription, ListResult)      -> m (Either String ())-set' input@(_, ListResult {..}) = do+set' input@(_, lTool, _, ListResult {..}) = do   settings <- liftIO $ readIORef settings'    let run =@@ -406,11 +388,7 @@    run (do       case lTool of-        GHC   -> liftE $ setGHC (GHCTargetVersion lCross lVer) SetGHCOnly Nothing $> ()-        Cabal -> liftE $ setCabal lVer $> ()-        HLS   -> liftE $ setHLS lVer SetHLSOnly Nothing $> ()-        Stack -> liftE $ setStack lVer $> ()-        GHCup -> do+        Tool "ghcup" -> do           promptAnswer <- getUserPromptResponse             "Switching GHCup versions is not supported.\nDo you want to install the latest version? [Y/n]: "             PromptYes@@ -418,6 +396,7 @@                 PromptYes -> do                   void $ liftE $ upgradeGHCup Nothing False False                 PromptNo -> pure ()+        _ -> liftE $ setToolVersion lTool (TargetVersion lCross lVer) $> ()     )     >>= \case           VRight _ -> pure $ Right ()@@ -443,7 +422,7 @@              _ -> pure $ Left (prettyHFError e) -logGHCPostRm :: (MonadReader env m, HasLog env, MonadIO m) => GHCTargetVersion -> m ()+logGHCPostRm :: (MonadReader env m, HasLog env, MonadIO m) => TargetVersion -> m () logGHCPostRm ghcVer = do   cabalStore <- liftIO $ handleIO (\_ -> if isWindows then pure "C:\\cabal\\store" else pure "~/.cabal/store or ~/.local/state/cabal/store")     getStoreDir@@ -452,40 +431,37 @@   del' :: (MonadReader AppState m, MonadIO m, MonadFail m, MonadMask m, MonadUnliftIO m)-     => (Int, ListResult)+     => (Int, Tool, Maybe ToolDescription, ListResult)      -> m (Either String ())-del' (_, ListResult {..}) = do+del' (_, lTool, _, ListResult {..}) = do   AppState { ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask -  let run = runE @'[NotInstalled, UninstallFailed]+  let run = runE @'[NotInstalled, UninstallFailed, ParseError, MalformedInstallInfo]    run (do-      let vi = getVersionInfo crossVer lTool dls+      let vi = getVersionMetadata crossVer lTool dls       case lTool of-        GHC   -> liftE $ rmGHCVer crossVer $> vi-        Cabal -> liftE $ rmCabalVer lVer $> vi-        HLS   -> liftE $ rmHLSVer lVer $> vi-        Stack -> liftE $ rmStackVer lVer $> vi-        GHCup -> pure Nothing+        Tool "ghcup" -> pure Nothing+        _            -> liftE $ rmToolVersion lTool crossVer $> vi     )     >>= \case           VRight vi -> do-            when (lTool == GHC) $ logGHCPostRm crossVer-            logInfo $ "Successfuly removed " <> T.pack (prettyShow lTool) <> " " <> (if lTool == GHC then tVerToText crossVer else prettyVer lVer)-            forM_ (_viPostRemove =<< vi) $ \msg ->+            when (lTool == ghc) $ logGHCPostRm crossVer+            logInfo $ "Successfully removed " <> T.pack (prettyShow lTool) <> " " <> (if lTool == ghc then tVerToText crossVer else prettyVer lVer)+            forM_ (_vmPostRemove =<< vi) $ \msg ->               logInfo msg             pure $ Right ()           VLeft  e -> pure $ Left (prettyHFError e)  where-  crossVer = GHCTargetVersion lCross lVer+  crossVer = TargetVersion lCross lVer   changelog' :: (MonadReader AppState m, MonadIO m)-           => (Int, ListResult)+           => (Int, Tool, Maybe ToolDescription, ListResult)            -> m (Either String ())-changelog' (_, ListResult {..}) = do+changelog' (_, lTool, _, ListResult {..}) = do   AppState { pfreq, ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask-  case getChangeLog dls lTool (ToolVersion lVer) of+  case getChangeLog dls lTool (mkTVer lVer) of     Nothing -> pure $ Left $       "Could not find ChangeLog for " <> prettyShow lTool <> ", version " <> T.unpack (prettyVer lVer)     Just uri -> do@@ -495,8 +471,8 @@             FreeBSD -> exec "xdg-open" [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing             OpenBSD -> exec "xdg-open" [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing             Windows -> do-              let args = "start \"\" " ++ (T.unpack $ decUTF8Safe $ serializeURIRef' uri)-              c <- liftIO $ system $ args+              let args = "start \"\" " ++ T.unpack (decUTF8Safe $ serializeURIRef' uri)+              c <- liftIO $ system args               case c of                  (ExitFailure xi) -> pure $ Left $ NonZeroExit xi "cmd.exe" [args]                  ExitSuccess -> pure $ Right ()@@ -505,9 +481,9 @@         Right _ -> pure $ Right ()         Left  e -> pure $ Left $ prettyHFError e -compileGHC :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, MonadMask m, MonadUnliftIO m, Alternative m)-           => CompileGHC.CompileGHCOptions -> (Int, ListResult) -> m (Either String ())-compileGHC compopts (_, lr@ListResult{lTool = GHC, ..}) = do+compileGHC :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, MonadMask m, MonadUnliftIO m)+           => CompileGHC.CompileGHCOptions -> (Int, Tool, Maybe ToolDescription, ListResult) -> m (Either String ())+compileGHC compopts (_, Tool "ghc", _, lr@ListResult{..}) = do   appstate <- ask   let run =         runResourceT@@ -535,6 +511,10 @@                   , UninstallFailed                   , MergeFileTreeError                   , URIParseError+                  , ParseError+                  , FileAlreadyExistsError+                  , NoInstallInfo+                  , MalformedInstallInfo                   ]   compileResult <- run (do       AppState { ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask@@ -542,20 +522,20 @@         Just ref -> pure (GHC.GitDist (GitBranch ref Nothing))         Nothing -> do           -- Compile the version user is pointing to in the tui-          let vi = getVersionInfo (mkTVer lVer) GHC dls-          forM_ (_viPreInstall =<< vi) $ \msg -> do+          let vi = getVersionMetadata (mkTVer lVer) ghc dls+          forM_ (_vmPreInstall =<< vi) $ \msg -> do             lift $ logWarn msg             lift $ logWarn               "...waiting for 5 seconds, you can still abort..."             liftIO $ threadDelay 5000000 -- give the user a sec to intervene-          forM_ (_viPreCompile =<< vi) $ \msg -> do+          forM_ (_vmPreCompile =<< vi) $ \msg -> do             logInfo msg             logInfo               "...waiting for 5 seconds, you can still abort..."             liftIO $ threadDelay 5000000 -- for compilation, give the user a sec to intervene           pure (GHC.SourceDist lVer) -      targetVer <- liftE $ GHCup.compileGHC+      targetVer <- liftE $ GHC.compileGHC                     ghcVer                     (compopts ^. CompileGHC.crossTarget)                     (compopts ^. CompileGHC.overwriteVer)@@ -564,27 +544,27 @@                     (compopts ^. CompileGHC.jobs)                     (compopts ^. CompileGHC.buildConfig)                     (compopts ^. CompileGHC.patches)-                    (compopts ^. CompileGHC.addConfArgs)+                    (fmap T.unpack $ compopts ^. CompileGHC.addConfArgs)                     (compopts ^. CompileGHC.buildFlavour)                     (compopts ^. CompileGHC.buildSystem)                     (maybe GHCupInternal IsolateDir $ compopts ^. CompileGHC.isolateDir)-                    (compopts ^. CompileGHC.installTargets)+                    (fmap (words . T.unpack) $ compopts ^. CompileGHC.installTargets)       AppState { ghcupInfo = GHCupInfo { _ghcupDownloads = dls2 }} <- ask-      let vi2 = getVersionInfo targetVer GHC dls2+      let vi2 = getVersionMetadata targetVer ghc dls2       when         (compopts ^. CompileGHC.setCompile)-        (liftE . void $ GHCup.setGHC targetVer SetGHCOnly Nothing)+        (liftE . void $ setToolVersion ghc targetVer)       pure (vi2, targetVer)       )   case compileResult of       VRight (vi, tv) -> do         logInfo "GHC successfully compiled and installed"-        forM_ (_viPostInstall =<< vi) $ \msg -> logInfo msg+        forM_ (_vmPostInstall =<< vi) $ \msg -> logInfo msg         liftIO $ putStr (T.unpack $ tVerToText tv)         pure $ Right ()       VLeft (V (AlreadyInstalled _ v)) -> do         pure $ Left $-          "GHC ver " <> T.unpack (prettyVer v) <> " already installed, remove it first to reinstall"+          "GHC ver " <> prettyShow v <> " already installed, remove it first to reinstall"       VLeft (V (DirNotEmpty fp)) -> do         pure $ Left $           "Install directory " <> fp <> " is not empty."@@ -592,20 +572,19 @@         case keepDirs (appstate & settings) of           Never -> prettyHFError err           _ -> prettyHFError err <> "\n"-            <> "Check the logs at " <> (fromGHCupPath $ appstate & dirs & logsDir)+            <> "Check the logs at " <> fromGHCupPath (appstate & dirs & logsDir)             <> " and the build directory "             <> tmpdir <> " for more clues." <> "\n"             <> "Make sure to clean up " <> tmpdir <> " afterwards."       VLeft e -> do         pure $ Left $ prettyHFError e -- This is the case when the tool is not GHC... which should be impossible but,--- it exhaustes pattern matches-compileGHC _ (_, ListResult{lTool = _}) = pure (Right ())-+-- it exhausts pattern matches+compileGHC _ (_, _, _, _) = pure (Right ()) -compileHLS :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, MonadMask m, MonadUnliftIO m, Alternative m)-           => CompileHLS.CompileHLSOptions -> (Int, ListResult) -> m (Either String ())-compileHLS compopts (_, lr@ListResult{lTool = HLS, ..}) = do+compileHLS :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, MonadMask m, MonadUnliftIO m)+           => CompileHLS.CompileHLSOptions -> (Int, Tool, Maybe ToolDescription, ListResult) -> m (Either String ())+compileHLS compopts (_, Tool "hls", _, lr@ListResult{..}) = do   appstate <- ask   let run =         runResourceT@@ -631,6 +610,7 @@                   , UninstallFailed                   , MergeFileTreeError                   , URIParseError+                  , ParseError                   ]   compileResult <- run (do       AppState { ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask@@ -638,23 +618,26 @@         Just ref -> pure (HLS.GitDist (GitBranch ref Nothing))         Nothing -> do           -- Compile the version user is pointing to in the tui-          let vi = getVersionInfo (mkTVer lVer) HLS dls-          forM_ (_viPreInstall =<< vi) $ \msg -> do+          let vi = getVersionMetadata (mkTVer lVer) hls dls+          forM_ (_vmPreInstall =<< vi) $ \msg -> do             lift $ logWarn msg             lift $ logWarn               "...waiting for 5 seconds, you can still abort..."             liftIO $ threadDelay 5000000 -- give the user a sec to intervene-          forM_ (_viPreCompile =<< vi) $ \msg -> do+          forM_ (_vmPreCompile =<< vi) $ \msg -> do             logInfo msg             logInfo               "...waiting for 5 seconds, you can still abort..."             liftIO $ threadDelay 5000000 -- for compilation, give the user a sec to intervene           pure (HLS.SourceDist lVer) -      ghcs <-+      ghcs' <-         liftE $ forM (compopts ^. CompileHLS.targetGHCs)-                     (\ghc -> fmap (_tvVersion . fst) . Utils.fromVersion (Just ghc) GStrict $ GHC)-      targetVer <- liftE $ GHCup.compileHLS+                     (\ghc' -> Utils.resolveVersion (Just ghc') GStrict ghc)+      ghcs <- forM ghcs' $ \TargetVersionReq{..} -> do+        when (isJust $ _tvTarget _tvqTargetVer) $ fail "Cannot compile HLS for a cross GHC"+        pure (_tvVersion _tvqTargetVer)+      targetVer <- liftE $ HLS.compileHLS                       hlsVer                       ghcs                       (compopts ^. CompileHLS.jobs)@@ -666,23 +649,23 @@                       (compopts ^. CompileHLS.patches)                       (compopts ^. CompileHLS.cabalArgs)       AppState { ghcupInfo = GHCupInfo { _ghcupDownloads = dls2 }} <- ask-      let vi2 = getVersionInfo (mkTVer targetVer) GHC dls2+      let vi2 = getVersionMetadata (mkTVer targetVer) ghc dls2       when         (compopts ^. CompileHLS.setCompile)-        (liftE . void $ GHCup.setHLS targetVer SetHLSOnly Nothing)+        (liftE . void $ setToolVersion hls (mkTVer targetVer))       pure (vi2, targetVer)       )   case compileResult of       VRight (vi, tv) -> do         logInfo "HLS successfully compiled and installed"-        forM_ (_viPostInstall =<< vi) $ \msg -> logInfo msg+        forM_ (_vmPostInstall =<< vi) $ \msg -> logInfo msg         liftIO $ putStr (T.unpack $ prettyVer tv)         pure $ Right ()       VLeft err@(V (BuildFailed tmpdir _)) -> pure $ Left $         case keepDirs (appstate & settings) of           Never -> prettyHFError err           _ -> prettyHFError err <> "\n"-            <> "Check the logs at " <> (fromGHCupPath $ appstate & dirs & logsDir)+            <> "Check the logs at " <> fromGHCupPath (appstate & dirs & logsDir)                <> " and the build directory "             <> tmpdir <> " for more clues." <> "\n"             <> "Make sure to clean up " <> tmpdir <> " afterwards."@@ -690,14 +673,14 @@         pure $ Left $ prettyHFError e -- This is the case when the tool is not HLS... which should be impossible but, -- it exhaustes pattern matches-compileHLS _ (_, ListResult{lTool = _}) = pure (Right ())+compileHLS _ (_, _, _, _) = pure (Right ())   settings' :: IORef AppState {-# NOINLINE settings' #-} settings' = unsafePerformIO $ do   dirs <- getAllDirs-  let loggerConfig = LoggerConfig { lcPrintDebug  = False+  let loggerConfig = LoggerConfig { lcPrintDebugLvl = Nothing                                   , consoleOutter = \_ -> pure ()                                   , fileOutter    = \_ -> pure ()                                   , fancyColors   = True@@ -705,7 +688,7 @@   newIORef $ AppState defaultSettings                       dirs                       defaultKeyBindings-                      (GHCupInfo mempty mempty Nothing)+                      (GHCupInfo mempty (GHCupDownloads mempty) Nothing)                       (PlatformRequest A_64 Darwin Nothing)                       loggerConfig @@ -716,7 +699,7 @@    r <-     flip runReaderT settings-    . runE @'[DigestError, ContentLengthError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError, StackPlatformDetectError]+    . runE @'[DigestError, ContentLengthError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError, StackPlatformDetectError, UnsupportedMetadataFormat]     $ do       pfreq <- lift getPlatformReq       liftE $ getDownloadsF pfreq@@ -733,56 +716,82 @@   liftIO $ modifyIORef settings' (\s -> s { ghcupInfo = r })   settings <- liftIO $ readIORef settings' -  flip runReaderT settings $ do-    lV <- listVersions Nothing [] False True (Nothing, Nothing)-    pure $ BrickData (reverse lV)+  r' <- lift $ flip runReaderT settings $ runE $ do+    lV <- listVersions Nothing [] ShowUpdates False True (Nothing, Nothing)+    pure $ BrickData lV+  ExceptT $ pure $  either (Left . prettyHFError) Right $ veitherToEither r'  -- -keyHandlers :: KeyBindings+keyHandlersToolList :: KeyBindings             -> [ ( KeyCombination-                 , BrickSettings -> String+                 , Maybe (BrickSettings -> String)                  , Brick.EventM Name BrickState ()                  )                ]-keyHandlers KeyBindings {..} =-  [ (bQuit, const "Quit"     , Brick.halt)-  , (bInstall, const "Install"  , withIOAction install')-  , (bUninstall, const "Uninstall", withIOAction del')-  , (bSet, const "Set"      , withIOAction set')-  , (bChangelog, const "ChangeLog", withIOAction changelog')+keyHandlersToolList KeyBindings {..} =+  [ (bQuit, Just $ const "Quit"     , Brick.halt)+  , (bInstall, Just $ const "Install and set recommended version",+       withIOActionRecommended $ installWithOptions (AdvancedInstall.InstallOptions Nothing True Nothing Nothing False [] Nothing))   , ( bShowAllVersions-    , \BrickSettings {..} ->+    , Just $ \BrickSettings {..} ->        if _showAllVersions then "Don't show all versions" else "Show all versions"     , hideShowHandler' (not . _showAllVersions)     )-  , (bUp, const "Up", Common.zoom appState moveUp)-  , (bDown, const "Down", Common.zoom appState moveDown)-  , (KeyCombination (Vty.KChar 'h') [], const "help", mode .= KeyInfo)-  , (KeyCombination Vty.KEnter [], const "advance options", createMenuforTool )+  , (KeyCombination (Vty.KChar 'h') [], Just $ const "help", mode .= KeyInfo)+  , (KeyCombination Vty.KEnter [], Just $ const "Show tool details", mode .= Common.ToolInfo )+  , (KeyCombination KLeft [], Nothing, versionFocus .= False)+  , (KeyCombination KRight [], Nothing, versionFocus .= True)+  , (KeyCombination (Vty.KChar '\t') [], Nothing, versionFocus %= not)   ]++keyHandlersVersionList :: KeyBindings+            -> [ ( KeyCombination+                 , Maybe (BrickSettings -> String)+                 , Brick.EventM Name BrickState ()+                 )+               ]+keyHandlersVersionList KeyBindings {..} =+  [ (bQuit, Just $ const "Quit"     , Brick.halt)+  , (bInstall, Just $ const "Install"  , withIOAction install')+  , (bUninstall, Just $ const "Uninstall", withIOAction del')+  , (bSet, Just $ const "Set"      , withIOAction set')+  , (bChangelog, Just $ const "ChangeLog", withIOAction changelog')+  , ( bShowAllVersions+    , Just $ \BrickSettings {..} ->+       if _showAllVersions then "Don't show all versions" else "Show all versions"+    , hideShowHandler' (not . _showAllVersions)+    )+  , (KeyCombination (Vty.KChar 'h') [], Just $ const "Help", mode .= KeyInfo)+  , (KeyCombination Vty.KEnter [], Just $ const "Advanced options", createMenuforTool )+  , (KeyCombination KLeft [], Nothing, versionFocus .= False)+  , (KeyCombination KRight [], Nothing, versionFocus .= True)+  , (KeyCombination (Vty.KChar '\t') [], Nothing, versionFocus %= not)+  ]  where   createMenuforTool = do-    e <- use (appState % to sectionListSelectedElement)+    e <- use (appState % to L.listSelectedElement)     case e of-      Nothing     -> pure ()-      Just (_, r) -> do-        -- Create new ContextMenu, but maintain the state of Install/Compile-        -- menus. This is especially useful in case the user made a typo and-        -- would like to retry the action.-        contextMenu .= ContextMenu.create r-          (MenuKeyBindings { mKbUp = bUp, mKbDown = bDown, mKbQuit = bQuit})-        -- Set mode to context-        mode           .= ContextPanel+      Nothing -> pure ()+      Just (_, (t, (td, vlr))) -> case L.listSelectedElement vlr of+        Just (_, lr) -> do+          -- Create new ContextMenu, but maintain the state of Install/Compile+          -- menus. This is especially useful in case the user made a typo and+          -- would like to retry the action.+          contextMenu .= ContextMenu.create (t, (td, lr))+            (MenuKeyBindings { mKbUp = bUp, mKbDown = bDown, mKbQuit = bQuit})+          -- Set mode to context+          mode           .= ContextPanel+        Nothing -> pure ()     pure () -  --hideShowHandler' :: (BrickSettings -> Bool) -> (BrickSettings -> Bool) -> m ()-  hideShowHandler' f = do-    app_settings <- use appSettings-    let-      vers = f app_settings-      newAppSettings = app_settings & Common.showAllVersions .~ vers-    ad <- use appData-    current_app_state <- use appState-    appSettings .= newAppSettings-    appState    .= constructList ad newAppSettings (Just current_app_state)+hideShowHandler' :: (BrickSettings -> Bool) -> Brick.EventM Name BrickState ()+hideShowHandler' f = do+  app_settings <- use appSettings+  let+    vers = f app_settings+    newAppSettings = app_settings & Common.showAllVersions .~ vers+  ad <- use appData+  current_app_state <- use appState+  appSettings .= newAppSettings+  appState    .= constructList ad newAppSettings (Just current_app_state)
lib-tui/GHCup/Brick/App.hs view
@@ -13,7 +13,7 @@ - Pattern match on the Mode - Dispatch drawing/events to the corresponding widget/s -In general each widget should know how to draw itself and how to handle its own events, so this+In general, each widget should know how to draw itself and how to handle its own events, so this module should only contain:  - how to draw non-widget information. For example the footer@@ -25,18 +25,19 @@  import qualified GHCup.Brick.Actions as Actions import qualified GHCup.Brick.Attributes as Attributes-import GHCup.Brick.BrickState (BrickState (..), advanceInstallMenu, appKeys, appSettings, appState, contextMenu, mode, compileGHCMenu, compileHLSMenu)+import GHCup.Brick.BrickState (BrickState (..), advancedInstallMenu, appKeys, appSettings, appState, contextMenu, mode, compileGHCMenu, compileHLSMenu, versionFocus) import GHCup.Brick.Common (Mode (..), Name (..)) import qualified GHCup.Brick.Common as Common import qualified GHCup.Brick.Widgets.KeyInfo as KeyInfo+import qualified GHCup.Brick.Widgets.ToolInfo as ToolInfo import qualified GHCup.Brick.Widgets.Menus.Context as ContextMenu import qualified GHCup.Brick.Widgets.Navigation as Navigation import qualified GHCup.Brick.Widgets.Tutorial as Tutorial import qualified GHCup.Brick.Widgets.Menu as Menu-import qualified GHCup.Brick.Widgets.Menus.AdvanceInstall as AdvanceInstall+import qualified GHCup.Brick.Widgets.Menus.AdvancedInstall as AdvancedInstall -import GHCup.List (ListResult)-import GHCup.Types (AppState (AppState, keyBindings), KeyCombination (KeyCombination), KeyBindings (..))+import GHCup.Command.List (ListResult)+import GHCup.Types (AppState (AppState, keyBindings), KeyCombination (KeyCombination), KeyBindings (..), Tool, ToolDescription)  import qualified Brick.Focus as F import Brick (@@ -68,6 +69,7 @@ import qualified GHCup.Brick.Widgets.Menus.CompileGHC as CompileGHC import qualified GHCup.Brick.Widgets.Menus.CompileHLS as CompileHLS import Control.Monad (void, when)+import Control.Monad.State.Class (get)  app :: AttrMap -> AttrMap -> App BrickState () Name app attrs dimAttrs =@@ -93,17 +95,22 @@       . Brick.txtWrap       . T.pack       . foldr1 (\x y -> x <> "  " <> y)-      . fmap (\(KeyCombination key mods, pretty_setting, _)-                  -> intercalate "+" (Common.showKey key : (Common.showMod <$> mods)) <> ":" <> pretty_setting (st ^. appSettings)+      . fmap (\(KeyCombination key mods, mpretty_setting, _) ->+                 case mpretty_setting of+                   Just pretty_setting -> intercalate "+" (Common.showKey key : (Common.showMod <$> mods)) <> ":" <> pretty_setting (st ^. appSettings)+                   Nothing -> ""              )-      $ Actions.keyHandlers (st ^. appKeys)-    navg = Navigation.draw dimAttrs (st ^. appState) <=> footer+      $ if st ^. versionFocus+         then Actions.keyHandlersVersionList (st ^. appKeys)+         else Actions.keyHandlersToolList (st ^. appKeys)+    navg = Navigation.draw (st ^. versionFocus) dimAttrs (st ^. appState) <=> footer   in case st ^. mode of        Navigation   -> [navg]        Tutorial     -> [Tutorial.draw (bQuit $ st ^. appKeys), navg]        KeyInfo      -> [KeyInfo.draw (st ^. appKeys), navg]+       ToolInfo     -> [ToolInfo.draw (st ^. appState) (st ^. appKeys), navg]        ContextPanel -> [ContextMenu.draw (st ^. contextMenu), navg]-       AdvanceInstallPanel -> AdvanceInstall.draw (st ^. advanceInstallMenu) ++ [navg]+       AdvancedInstallPanel -> AdvancedInstall.draw (st ^. advancedInstallMenu) ++ [navg]        CompileGHCPanel     -> CompileGHC.draw (st ^. compileGHCMenu) ++ [navg]        CompileHLSPanel     -> CompileHLS.draw (st ^. compileHLSMenu) ++ [navg] @@ -118,6 +125,14 @@       | bQuit kb == KeyCombination key mods -> mode .= Navigation     _ -> pure () +toolInfoHandler :: BrickEvent Name e -> EventM Name BrickState ()+toolInfoHandler ev = do+  AppState { keyBindings = kb } <- liftIO $ readIORef Actions.settings'+  case ev of+    VtyEvent (Vty.EvKey key mods)+      | bQuit kb == KeyCombination key mods -> mode .= Navigation+    _ -> pure ()+ -- | On q, go back to navigation. Else, do nothing tutorialHandler :: BrickEvent Name e -> EventM Name BrickState () tutorialHandler ev = do@@ -130,13 +145,19 @@ -- | Tab/Arrows to navigate. navigationHandler :: BrickEvent Name e -> EventM Name BrickState () navigationHandler ev = do+  BrickState{..} <- get   AppState { keyBindings = kb } <- liftIO $ readIORef Actions.settings'   case ev of-    inner_event@(VtyEvent (Vty.EvKey key mods)) ->-      case find (\(key', _, _) -> key' == KeyCombination key mods) (Actions.keyHandlers kb) of-        Just (_, _, handler) -> handler-        Nothing -> void $ Common.zoom appState $ Navigation.handler inner_event-    inner_event -> Common.zoom appState $ Navigation.handler inner_event+    inner_event@(VtyEvent (Vty.EvKey key mods))+      | _versionFocus -> do+          case find (\(key', _, _) -> key' == KeyCombination key mods) (Actions.keyHandlersVersionList kb) of+            Just (_, _, handler) -> handler+            Nothing -> void $ Common.zoom appState $ Navigation.handler _versionFocus inner_event+      | otherwise -> do+          case find (\(key', _, _) -> key' == KeyCombination key mods) (Actions.keyHandlersToolList kb) of+            Just (_, _, handler) -> handler+            Nothing -> void $ Common.zoom appState $ Navigation.handler _versionFocus inner_event+    inner_event -> Common.zoom appState $ Navigation.handler _versionFocus inner_event  contextMenuHandler :: BrickEvent Name e -> EventM Name BrickState () contextMenuHandler ev = do@@ -146,13 +167,13 @@   case (ev, focusedElement) of     (_ , Nothing) -> pure ()     (VtyEvent (Vty.EvKey k m), Just n) |  k == exitKey && m == mods -> mode .= Navigation-    (VtyEvent (Vty.EvKey Vty.KEnter []),  Just (Common.MenuElement Common.AdvanceInstallButton) ) -> mode .= Common.AdvanceInstallPanel+    (VtyEvent (Vty.EvKey Vty.KEnter []),  Just (Common.MenuElement Common.AdvancedInstallButton) ) -> mode .= Common.AdvancedInstallPanel     (VtyEvent (Vty.EvKey Vty.KEnter []),  Just (Common.MenuElement Common.CompileGHCButton) ) -> mode .= Common.CompileGHCPanel     (VtyEvent (Vty.EvKey Vty.KEnter []),  Just (Common.MenuElement Common.CompileHLSButton) ) -> mode .= Common.CompileHLSPanel     _ -> Common.zoom contextMenu $ ContextMenu.handler ev ---advanceInstallHandler :: BrickEvent Name e -> EventM Name BrickState ()-advanceInstallHandler = menuWithOverlayHandler advanceInstallMenu Actions.installWithOptions AdvanceInstall.handler+advancedInstallHandler :: BrickEvent Name e -> EventM Name BrickState ()+advancedInstallHandler = menuWithOverlayHandler advancedInstallMenu Actions.installWithOptions AdvancedInstall.handler  compileGHCHandler :: BrickEvent Name e -> EventM Name BrickState () compileGHCHandler = menuWithOverlayHandler compileGHCMenu Actions.compileGHC CompileGHC.handler@@ -162,8 +183,9 @@  -- | Passes all events to innerHandler if an overlay is opened -- else handles the exitKey and Enter key for the Menu's "OkButton"-menuWithOverlayHandler :: Lens' BrickState (Menu.Menu t Name)-  -> (t -> ((Int, ListResult) -> ReaderT AppState IO (Either String a)))+menuWithOverlayHandler ::+     Lens' BrickState (Menu.Menu t Name)+  -> (t -> ((Int, Tool, Maybe ToolDescription, ListResult) -> ReaderT AppState IO (Either String a)))   -> (BrickEvent Name e -> EventM Name (Menu.Menu t Name) ())   -> BrickEvent Name e   -> EventM Name BrickState ()@@ -187,9 +209,10 @@   m <- use mode   case m of     KeyInfo      -> keyInfoHandler ev+    ToolInfo     -> toolInfoHandler ev     Tutorial     -> tutorialHandler ev     Navigation   -> navigationHandler ev     ContextPanel -> contextMenuHandler ev-    AdvanceInstallPanel -> advanceInstallHandler ev+    AdvancedInstallPanel -> advancedInstallHandler ev     CompileGHCPanel     -> compileGHCHandler ev     CompileHLSPanel     -> compileHLSHandler ev
lib-tui/GHCup/Brick/Attributes.hs view
@@ -39,7 +39,7 @@   , (strayAttr                 , Vty.defAttr `withForeColor` Vty.brightCyan)   , (dayAttr                   , Vty.defAttr `withForeColor` Vty.brightCyan)   , (helpAttr                  , Vty.defAttr `withStyle`     Vty.italic)-  , (hoorayAttr                , Vty.defAttr `withForeColor` Vty.brightWhite)+  , (hoorayAttr                , Vty.defAttr `withStyle`     Vty.bold)   , (helpMsgAttr               , Vty.defAttr `withForeColor` Vty.yellow)   , (errMsgAttr                , Vty.defAttr `withForeColor` Vty.red)   ]
lib-tui/GHCup/Brick/BrickState.hs view
@@ -32,22 +32,23 @@ import GHCup.Brick.Common             ( BrickData(..), BrickSettings(..), Mode(..)) import GHCup.Brick.Widgets.Navigation ( BrickInternalState) import GHCup.Brick.Widgets.Menus.Context (ContextMenu)-import GHCup.Brick.Widgets.Menus.AdvanceInstall (AdvanceInstallMenu)+import GHCup.Brick.Widgets.Menus.AdvancedInstall (AdvancedInstallMenu) import GHCup.Brick.Widgets.Menus.CompileGHC (CompileGHCMenu) import Optics.TH                      (makeLenses) import GHCup.Brick.Widgets.Menus.CompileHLS (CompileHLSMenu)   data BrickState = BrickState-  { _appData            :: BrickData-  , _appSettings        :: BrickSettings-  , _appState           :: BrickInternalState-  , _contextMenu        :: ContextMenu-  , _advanceInstallMenu :: AdvanceInstallMenu-  , _compileGHCMenu     :: CompileGHCMenu-  , _compileHLSMenu     :: CompileHLSMenu-  , _appKeys            :: KeyBindings-  , _mode               :: Mode+  { _appData             :: BrickData+  , _appSettings         :: BrickSettings+  , _appState            :: BrickInternalState+  , _contextMenu         :: ContextMenu+  , _advancedInstallMenu :: AdvancedInstallMenu+  , _compileGHCMenu      :: CompileGHCMenu+  , _compileHLSMenu      :: CompileHLSMenu+  , _appKeys             :: KeyBindings+  , _mode                :: Mode+  , _versionFocus        :: Bool   }   --deriving Show 
lib-tui/GHCup/Brick/Common.hs view
@@ -45,13 +45,13 @@       UrlEditBox, SetCheckBox, IsolateEditBox, ForceCheckBox, AdditionalEditBox     , TargetGhcEditBox, BootstrapGhcEditBox, HadrianGhcEditBox, JobsEditBox, BuildConfigEditBox     , PatchesEditBox, CrossTargetEditBox, AddConfArgsEditBox, OvewrwiteVerEditBox-    , BuildFlavourEditBox, BuildSystemEditBox, OkButton, AdvanceInstallButton+    , BuildFlavourEditBox, BuildSystemEditBox, OkButton, AdvancedInstallButton     , CompileGHCButton, CompileHLSButton, CabalProjectEditBox     , CabalProjectLocalEditBox, UpdateCabalCheckBox, GitRefEditBox     , BootstrapGhcSelectBox, HadrianGhcSelectBox, ToolVersionBox, GHCInstallTargets   ) ) where -import           GHCup.List ( ListResult )+import           GHCup.Command.List ( ToolListResult ) import           GHCup.Prelude ( isWindows ) import           GHCup.Types ( Tool, KeyCombination (KeyCombination) ) import Data.List (intercalate)@@ -77,8 +77,8 @@  pattern OkButton :: ResourceId pattern OkButton = ResourceId 0-pattern AdvanceInstallButton :: ResourceId-pattern AdvanceInstallButton = ResourceId 100+pattern AdvancedInstallButton :: ResourceId+pattern AdvancedInstallButton = ResourceId 100 pattern CompileGHCButton :: ResourceId pattern CompileGHCButton = ResourceId 101 pattern CompileHLSButton :: ResourceId@@ -145,11 +145,11 @@ data Name = AllTools                   -- ^ The main list widget           | Singular Tool              -- ^ The particular list for each tool           | ListItem Tool Int          -- ^ An item in list-          | KeyInfoBox                 -- ^ The text box widget with action informacion+          | KeyInfoBox                 -- ^ The text box widget with action information           | TutorialBox                -- ^ The tutorial widget           | ContextBox                 -- ^ The resource for Context Menu           | CompileGHCBox              -- ^ The resource for CompileGHC Menu-          | AdvanceInstallBox          -- ^ The resource for AdvanceInstall Menu+          | AdvancedInstallBox         -- ^ The resource for AdvancedInstall Menu           | MenuElement ResourceId     -- ^ Each element in a Menu. Resources must not be share for visible                                        --   Menus, but MenuA and MenuB can share resources if they both are                                        --   invisible, or just one of them is visible.@@ -159,9 +159,10 @@ -- | Mode type. It helps to dispatch events to different handlers. data Mode = Navigation           | KeyInfo+          | ToolInfo           | Tutorial           | ContextPanel-          | AdvanceInstallPanel+          | AdvancedInstallPanel           | CompileGHCPanel           | CompileHLSPanel           deriving (Eq, Show, Ord)@@ -206,10 +207,10 @@     Brick.centerLayer       . Brick.hLimitPercent 80       . Brick.vLimitPercent 75-      . Brick.withBorderStyle Border.unicode+      . Brick.withBorderStyle Border.unicodeBold       . Border.borderWithLabel (Brick.txt layer_name) --- | puts a cursor at the line beginning so It can be read by screen readers+-- | Puts a cursor at the line beginning so it can be read by screen readers enableScreenReader :: n -> Brick.Widget n -> Brick.Widget n enableScreenReader n = Brick.putCursor n (Brick.Location (0,0)) --                     |- tip: when debugging, use Brick.showCursor instead@@ -219,7 +220,7 @@ zoom l = Brick.zoom (toLensVL l)  data BrickData = BrickData-  { _lr    :: [ListResult]+  { _lr    :: ToolListResult   }   deriving Show 
lib-tui/GHCup/Brick/Widgets/KeyInfo.hs view
@@ -40,7 +40,12 @@             Brick.hBox [               Brick.txt "Press "             , Common.keyToWidget bUp, Brick.txt " and ", Common.keyToWidget bDown-            , Brick.txtWrap " to navigate the list of tools"+            , Brick.txtWrap " to select an element in the currently focused list (tools or versions)"+            ],+            Brick.hBox [+              Brick.txt "Press "+            , Brick.txt "← and → or TAB"+            , Brick.txtWrap " to switch between tool and version list"             ]           , Brick.hBox [               Brick.txt "Press "
lib-tui/GHCup/Brick/Widgets/Menu.hs view
@@ -34,14 +34,14 @@   b) a validator function   c) a handler and a renderer -We have to use existential types to achive a composable API since every FieldInput has a different+We have to use existential types to achieve a composable API since every FieldInput has a different internal type, and every MenuField has a different Lens. For example:   - The menu state is a record (MyRecord {uri: URI, flag : Bool})   - Then, there are two MenuField:     - One MenuField has (Lens' MyRecord URI) and the other has (Lens' MyRecord Bool)     - The MenuFields has FieldInputs with internal state Text and Bool, respectively-  - Obviously, the MenuField has to be polimorphic in the Lens' and in the Input internal state,-    But we must hide that polimorphisim (existential), in order to store all MenuField in a List+  - Obviously, the MenuField has to be polymorphic in the Lens' and in the Input internal state,+    But we must hide that polymorphism (existential), in order to store all MenuField in a List  ************** -} @@ -100,7 +100,7 @@ type ErrorMessage = T.Text data ErrorStatus = Valid | Invalid ErrorMessage deriving (Eq) --- | A lens which does nothing. Usefull to defined no-op fields+-- | A lens which does nothing. Useful to define no-op fields emptyLens :: Lens' s () emptyLens = lens (const ()) (\s _ -> s) @@ -156,7 +156,7 @@   { selectStateItems :: (NonEmpty (Int, (i, Bool)), Bool) -- ^ All items along with their selected state                                                           -- And Bool to indicate if editable field is selected   , selectStateEditState :: Maybe (Edit.Editor T.Text n)  -- ^ Editable field's editor state-  , selectStateFocusRing :: FocusRing Int                 -- ^ Focus ring using integeral values assigned to each item+  , selectStateFocusRing :: FocusRing Int                 -- ^ Focus ring using integral values assigned to each item   , selectStateOverlayOpen :: Bool                        -- ^ Whether the select menu is open   } @@ -199,7 +199,7 @@   where g (MenuField {..})= fieldInput ^. inputHelpL         s (MenuField{..}) msg = MenuField {fieldInput = fieldInput & inputHelpL .~ msg , ..} --- | How to draw a field given a formater+-- | How to draw a field given a formatter drawField :: Formatter n -> Bool -> MenuField s n -> Widget n drawField amp focus (MenuField { fieldInput = FieldInput {..}, ..}) =   let (input, overlay) = inputRender focus fieldStatus inputHelp fieldLabel inputState (amp focus)@@ -225,7 +225,7 @@ createCheckBoxInput :: FieldInput Bool Bool n createCheckBoxInput = FieldInput False Right "" checkBoxRender checkBoxHandler   where-    border w = Brick.txt "[" <+> (Brick.padRight (Brick.Pad 1) $ Brick.padLeft (Brick.Pad 2) w) <+> Brick.txt "]"+    border w = Brick.txt "[" <+> Brick.padRight (Brick.Pad 1) (Brick.padLeft (Brick.Pad 2) w) <+> Brick.txt "]"     drawBool b =         if b           then border . Brick.withAttr Attributes.installedAttr    $ Brick.str Common.checkBoxSelectedSign@@ -268,9 +268,9 @@                  | focus     -> borderBox editorContents                  | otherwise -> borderBox $ renderAsErrMsg msg         mOverlay = if overlayOpen-          then Just (overlayLayer ("Edit " <> label) $ overlay)+          then Just (overlayLayer ("Edit " <> label) overlay)           else Nothing-        overlay = Brick.vBox $+        overlay = Brick.vBox           [ Brick.txtWrap help           , Border.border $ Edit.renderEditor (Brick.txt . T.unlines) focus edi           , case errMsg of@@ -325,7 +325,7 @@ createSelectInput :: (Ord n, Show n)   => NonEmpty i   -> (i -> T.Text)-  -> (Int -> (NonEmpty (Int, (i, Bool)), Bool) -> ((NonEmpty (Int, (i, Bool))), Bool))+  -> (Int -> (NonEmpty (Int, (i, Bool)), Bool) -> (NonEmpty (Int, (i, Bool)), Bool))   -> (([i], Maybe T.Text) -> Either ErrorMessage k)   -> n   -> Maybe n@@ -341,10 +341,10 @@       (F.focusRing [1.. totalRows])       False     getSelectedItems (SelectState {..}) =-      ( fmap (fst . snd) . (filter (snd . snd)) . NE.toList . fst $ selectStateItems-      , if snd selectStateItems then (T.init . T.unlines . Edit.getEditContents <$> selectStateEditState) else Nothing)+      ( fmap (fst . snd) . filter (snd . snd) . NE.toList . fst $ selectStateItems+      , if snd selectStateItems then T.init . T.unlines . Edit.getEditContents <$> selectStateEditState else Nothing) -    border w = Brick.txt "[" <+> (Brick.padRight (Brick.Pad 1) $ Brick.padLeft (Brick.Pad 1) w) <+> Brick.txt "]"+    border w = Brick.txt "[" <+> Brick.padRight (Brick.Pad 1) (Brick.padLeft (Brick.Pad 1) w) <+> Brick.txt "]"     selectRender focus errMsg help label s amp = (field, mOverlay)       where         field =@@ -353,7 +353,7 @@                 (xs, mTxt) -> Just $ fmap (Brick.padRight (Brick.Pad 1) . Brick.txt . showItem) xs                    ++ (case mTxt of Just t -> [Brick.txt t]; Nothing -> [])           in amp $ case (errMsg, mContents) of-            (Valid, Nothing) -> (Brick.padLeft (Brick.Pad 1) . renderAsHelpMsg $ help)+            (Valid, Nothing) -> Brick.padLeft (Brick.Pad 1) . renderAsHelpMsg $ help             (Valid, Just contents) -> border $ Brick.hBox contents             (Invalid msg, Nothing)               | focus -> Brick.padLeft (Brick.Pad 1) . renderAsHelpMsg $ help@@ -365,16 +365,16 @@         mOverlay = if selectStateOverlayOpen s           then Just (overlayLayer ("Select " <> label)  $ overlay s errMsg help)           else Nothing-    overlay (SelectState {..}) errMsg help = Brick.vBox $+    overlay (SelectState {..}) errMsg help = Brick.vBox       [ if txtFieldFocused           then Brick.txtWrap "Press Enter to finish editing and select custom value. Press Up/Down keys to navigate"           else Brick.txt "Press "             <+> Common.keyToWidget (kb ^. mKbQuitL)             <+> Brick.txt " to go back, Press Enter to select"       , case errMsg of Invalid msg -> renderAsErrMsg msg; _ -> Brick.emptyWidget-      , Brick.vLimit (totalRows) $ Brick.withVScrollBars Brick.OnRight+      , Brick.vLimit totalRows $ Brick.withVScrollBars Brick.OnRight           $ Brick.viewport viewportFieldName Brick.Vertical-          $ Brick.vBox $ mEditableField ++ (NE.toList $ fmap (mkSelectRow focused) (fst selectStateItems))+          $ Brick.vBox $ mEditableField ++ NE.toList (fmap (mkSelectRow focused) (fst selectStateItems))       ]       where focused = fromMaybe 1 $ F.focusGetCurrent selectStateFocusRing             txtFieldFocused = focused == totalRows@@ -383,12 +383,12 @@               Nothing -> []      mkSelectRow focused (ix, (item, selected)) = (if focused == ix then Brick.visible else id) $-      Brick.txt "[" <+> (Brick.padRight (Brick.Pad 1) $ Brick.padLeft (Brick.Pad 1) m) <+> Brick.txt "] "-        <+> (renderAslabel (showItem item) (focused == ix))+      Brick.txt "[" <+> Brick.padRight (Brick.Pad 1) (Brick.padLeft (Brick.Pad 1) m) <+> Brick.txt "] "+        <+> renderAslabel (showItem item) (focused == ix)       where m = if selected then Brick.txt "*" else Brick.txt " "      mkEditTextRow focused edi selected help = (if focused then Brick.visible else id) $-      Brick.txt "[" <+> (Brick.padRight (Brick.Pad 1) $ Brick.padLeft (Brick.Pad 1) m) <+> Brick.txt "] "+      Brick.txt "[" <+> Brick.padRight (Brick.Pad 1) (Brick.padLeft (Brick.Pad 1) m) <+> Brick.txt "] "         <+> if not focused && Edit.getEditContents edi == [mempty]                then Brick.txt "(Specify custom text value)"                else Brick.vLimit 1 $ Border.vBorder <+> Brick.padRight Brick.Max (Edit.renderEditor (Brick.txt . T.unlines) focused edi) <+> Border.vBorder@@ -447,8 +447,8 @@     singleSelect :: Int -> (NonEmpty (Int, (i, Bool)), Bool) -> (NonEmpty (Int, (i, Bool)), Bool)     singleSelect ix (ne, a) = (fmap (\(ix', (i, b)) -> if ix' == ix then (ix', (i, True)) else (ix', (i, False))) ne, ix == length ne + 1) -    getSelection (_, Just txt) = either Left (Right . Left) $ validator txt-    getSelection (ls, _) = maybe (either Left (Right . Left) $ validator "") (Right . Right . NE.head) $ NE.nonEmpty ls+    getSelection (_, Just txt) = Left <$> validator txt+    getSelection (ls, _) = maybe (Left <$> validator "") (Right . Right . NE.head) $ NE.nonEmpty ls   {- *****************@@ -467,14 +467,14 @@     else Brick.txt t  -- | Creates a left align column.--- Example:       |- col2 is align dispite the length of col1+-- Example:       |- col2 is align despite the length of col1 --   row1_col1         row1_col2 --   row2_col1_large   row2_col2 leftify :: Int -> Brick.Widget n -> Brick.Widget n leftify i = Brick.hLimit i . Brick.padRight Brick.Max  -- | Creates a right align column.--- Example:       |- col2 is align dispite the length of col1+-- Example:       |- col2 is align despite the length of col1 --         row1_col1   row1_col2 --   row2_col1_large   row2_col2 rightify :: Int -> Brick.Widget n -> Brick.Widget n@@ -524,11 +524,18 @@   ''Menu  isValidMenu :: Menu s n -> Bool-isValidMenu m = (all isValidField $ menuFields m)-  && (case (menuValidator m) (menuState m) of { Nothing -> True; _ -> False })+isValidMenu m = all isValidField (menuFields m)+  && (case menuValidator m (menuState m) of { Nothing -> True; _ -> False }) -createMenu :: n -> s -> T.Text -> (s -> Maybe ErrorMessage)-  -> MenuKeyBindings -> [Button s n] -> [MenuField s n] -> Menu s n+createMenu ::+     n+  -> s+  -> T.Text+  -> (s -> Maybe ErrorMessage)+  -> MenuKeyBindings+  -> [Button s n]+  -> [MenuField s n]+  -> Menu s n createMenu n initial title validator keys buttons fields = Menu fields initial validator buttons ring keys n title   where ring = F.focusRing $ [field & fieldName | field <- fields] ++ [button & fieldName | button <- buttons] @@ -550,7 +557,7 @@               Just err -> menuButtonsL %= fmap (fieldStatusL .~ Invalid err)             else menuButtonsL %= fmap (fieldStatusL .~ Invalid "Some fields are invalid")           menuFieldsL .= updated_fields-  case (drawFieldOverlay =<< focusedField) of+  case drawFieldOverlay =<< focusedField of     Just _ -> case ev of       VtyEvent e -> propagateEvent e       _ -> pure ()@@ -600,7 +607,7 @@     -- A list of functions which draw a highlighted label with right padding at the left of a widget.     amplifiers =       let labelsWidgets = fmap renderAslabel fieldLabels-       in fmap (\f b -> ((rightify (maxWidth + 1) (f b <+> Brick.txt " ")) <+>) ) labelsWidgets+       in fmap (\f b -> (rightify (maxWidth + 1) (f b <+> Brick.txt " ") <+>) ) labelsWidgets     drawFields = fmap drawField amplifiers     fieldWidgets = zipWith (F.withFocusRing (menu ^. menuFocusRingL)) drawFields (menu ^. menuFieldsL) 
− lib-tui/GHCup/Brick/Widgets/Menus/AdvanceInstall.hs
@@ -1,135 +0,0 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TypeApplications  #-}-{-# LANGUAGE RankNTypes        #-}-{-# LANGUAGE ViewPatterns      #-}-{-# OPTIONS_GHC -Wno-unused-record-wildcards #-}-{-# OPTIONS_GHC -Wno-unused-matches #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TemplateHaskell   #-}-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE InstanceSigs #-}-{-# OPTIONS_GHC -Wno-incomplete-patterns #-}--module GHCup.Brick.Widgets.Menus.AdvanceInstall (-  InstallOptions (..),-  AdvanceInstallMenu,-  create,-  handler,-  draw,-  instBindistL,-  instSetL,-  instVersionL,-  isolateDirL,-  forceInstallL,-  addConfArgsL,-  installTargetsL,-) where--import GHCup.Types (GHCTargetVersion(..))-import GHCup.Brick.Widgets.Menu (Menu, MenuKeyBindings)-import qualified GHCup.Brick.Widgets.Menu as Menu-import           GHCup.Brick.Common(Name(..))-import Brick-    ( BrickEvent(..),-      EventM,-      Widget(..))-import           Prelude                 hiding ( appendFile )-import           Optics.TH (makeLensesFor)-import qualified GHCup.Brick.Common as Common-import URI.ByteString (URI)-import qualified Data.Text as T-import Data.Bifunctor (Bifunctor(..))-import Data.Function ((&))-import Optics ((.~))-import Data.Char (isSpace)-import qualified GHCup.Utils.Parsers as Utils--data InstallOptions = InstallOptions-  { instBindist  :: Maybe URI-  , instSet      :: Bool-  , instVersion :: Maybe GHCTargetVersion-  -- ^ User specified version to override default-  , isolateDir   :: Maybe FilePath-  , forceInstall :: Bool-  , addConfArgs  :: [T.Text]-  , installTargets :: T.Text-  } deriving (Eq, Show)--makeLensesFor [-   ("instBindist", "instBindistL")-  , ("instSet", "instSetL")-  , ("instVersion", "instVersionL")-  , ("isolateDir", "isolateDirL")-  , ("forceInstall", "forceInstallL")-  , ("addConfArgs", "addConfArgsL")-  , ("installTargets", "installTargetsL")-  ]-  ''InstallOptions--type AdvanceInstallMenu = Menu InstallOptions Name--create :: MenuKeyBindings -> AdvanceInstallMenu-create k = Menu.createMenu AdvanceInstallBox initialState "Advance Install" validator k [ok] fields-  where-    initialInstallTargets = "install"-    initialState = InstallOptions Nothing False Nothing Nothing False [] initialInstallTargets-    validator InstallOptions {..} = case (instSet, isolateDir) of-      (True, Just _) -> Just "Cannot set active when doing an isolated install"-      _ -> Nothing-    -- Brick's internal editor representation is [mempty].-    emptyEditor i = T.null i || (i == "\n")--    whenEmpty :: a -> (T.Text -> Either Menu.ErrorMessage a) -> T.Text -> Either Menu.ErrorMessage a-    whenEmpty emptyval f i = if not (emptyEditor i) then f i else Right emptyval--    uriValidator :: T.Text -> Either Menu.ErrorMessage (Maybe URI)-    uriValidator = whenEmpty Nothing (second Just . readUri)-      where readUri = first T.pack . Utils.uriParser . T.unpack--    filepathValidator :: T.Text -> Either Menu.ErrorMessage (Maybe FilePath)-    filepathValidator = whenEmpty Nothing (bimap T.pack Just . Utils.absolutePathParser . T.unpack)--    toolVersionValidator :: T.Text -> Either Menu.ErrorMessage (Maybe GHCTargetVersion)-    toolVersionValidator = whenEmpty Nothing (bimap T.pack Just . Utils.ghcVersionEither . T.unpack)--    additionalValidator :: T.Text -> Either Menu.ErrorMessage [T.Text]-    additionalValidator = Right . T.split isSpace--    fields =-      [ Menu.createEditableField (Common.MenuElement Common.UrlEditBox) uriValidator instBindistL-          & Menu.fieldLabelL .~ "url"-          & Menu.fieldHelpMsgL .~ "Install the specified version from this bindist"-      , Menu.createCheckBoxField (Common.MenuElement Common.SetCheckBox) instSetL-          & Menu.fieldLabelL .~ "set"-          & Menu.fieldHelpMsgL .~ "Set as active version after install"-      , Menu.createEditableField (Common.MenuElement Common.ToolVersionBox) toolVersionValidator instVersionL-          & Menu.fieldLabelL .~ "version"-          & Menu.fieldHelpMsgL .~ "Specify a custom version"-      , Menu.createEditableField' initialInstallTargets (Common.MenuElement Common.GHCInstallTargets) Right installTargetsL-          & Menu.fieldLabelL .~ "install-targets"-          & Menu.fieldHelpMsgL .~ "Specify space separated list of make install targets"-      , Menu.createEditableField (Common.MenuElement Common.IsolateEditBox) filepathValidator isolateDirL-          & Menu.fieldLabelL .~ "isolated"-          & Menu.fieldHelpMsgL .~ "install in an isolated absolute directory instead of the default one"-      , Menu.createCheckBoxField (Common.MenuElement Common.ForceCheckBox) forceInstallL-          & Menu.fieldLabelL .~ "force"-          & Menu.fieldHelpMsgL .~ "Force install (THIS IS UNSAFE, only use it in Dockerfiles or CI)"-      , Menu.createEditableField (Common.MenuElement Common.AdditionalEditBox) additionalValidator addConfArgsL-          & Menu.fieldLabelL .~ "CONFIGURE_ARGS"-          & Menu.fieldHelpMsgL .~ "Additional arguments to bindist configure"-      ]--    ok = Menu.createButtonField (Common.MenuElement Common.OkButton)-          & Menu.fieldLabelL .~ "Advance Install"-          & Menu.fieldHelpMsgL .~ "Install with options below"--handler :: BrickEvent Name e -> EventM Name AdvanceInstallMenu ()-handler = Menu.handlerMenu---draw :: AdvanceInstallMenu -> [Widget Name]-draw = Menu.drawMenu
+ lib-tui/GHCup/Brick/Widgets/Menus/AdvancedInstall.hs view
@@ -0,0 +1,137 @@+{-# LANGUAGE CPP               #-}+{-# LANGUAGE DataKinds         #-}+{-# LANGUAGE FlexibleContexts  #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications  #-}+{-# LANGUAGE RankNTypes        #-}+{-# LANGUAGE ViewPatterns      #-}+{-# OPTIONS_GHC -Wno-unused-record-wildcards #-}+{-# OPTIONS_GHC -Wno-unused-matches #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TemplateHaskell   #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE InstanceSigs #-}+{-# OPTIONS_GHC -Wno-incomplete-patterns #-}++module GHCup.Brick.Widgets.Menus.AdvancedInstall (+  InstallOptions (..),+  AdvancedInstallMenu,+  create,+  handler,+  draw,+  instBindistL,+  instSetL,+  instVersionL,+  isolateDirL,+  forceInstallL,+  addConfArgsL,+  installTargetsL,+) where++import GHCup.Types (TargetVersionReq(..))+import GHCup.Brick.Widgets.Menu (Menu, MenuKeyBindings)+import qualified GHCup.Brick.Widgets.Menu as Menu+import           GHCup.Brick.Common(Name(..))+import Brick+    ( BrickEvent(..),+      EventM,+      Widget(..))+import           Prelude                 hiding ( appendFile )+import           Optics.TH (makeLensesFor)+import qualified GHCup.Brick.Common as Common+import URI.ByteString (URI)+import qualified Data.Text as T+import Data.Bifunctor (Bifunctor(..))+import Data.Function ((&))+import Optics ((.~))+import Data.Char (isSpace)+import qualified GHCup.Input.Parsers as Utils++data InstallOptions = InstallOptions+  { instBindist  :: Maybe URI+  , instSet      :: Bool+  , instVersion :: Maybe TargetVersionReq+  -- ^ User specified version to override default+  , isolateDir   :: Maybe FilePath+  , forceInstall :: Bool+  , addConfArgs  :: [T.Text]+  , installTargets :: Maybe T.Text+  } deriving (Eq, Show)++makeLensesFor [+   ("instBindist", "instBindistL")+  , ("instSet", "instSetL")+  , ("instVersion", "instVersionL")+  , ("isolateDir", "isolateDirL")+  , ("forceInstall", "forceInstallL")+  , ("addConfArgs", "addConfArgsL")+  , ("installTargets", "installTargetsL")+  ]+  ''InstallOptions++type AdvancedInstallMenu = Menu InstallOptions Name++create :: MenuKeyBindings -> AdvancedInstallMenu+create k = Menu.createMenu AdvancedInstallBox initialState "Advanced Install" validator k [ok] fields+  where+    initialState = InstallOptions Nothing False Nothing Nothing False [] Nothing+    validator InstallOptions {..} = case (instSet, isolateDir) of+      (True, Just _) -> Just "Cannot set active when doing an isolated install"+      _ -> Nothing+    -- Brick's internal editor representation is [mempty].+    emptyEditor i = T.null i || (i == "\n")++    whenEmpty :: a -> (T.Text -> Either Menu.ErrorMessage a) -> T.Text -> Either Menu.ErrorMessage a+    whenEmpty emptyval f i = if not (emptyEditor i) then f i else Right emptyval++    uriValidator :: T.Text -> Either Menu.ErrorMessage (Maybe URI)+    uriValidator = whenEmpty Nothing (second Just . readUri)+      where readUri = first T.pack . Utils.uriParser . T.unpack++    filepathValidator :: T.Text -> Either Menu.ErrorMessage (Maybe FilePath)+    filepathValidator = whenEmpty Nothing (bimap T.pack Just . Utils.absolutePathParser . T.unpack)++    installTargetValidator :: T.Text -> Either Menu.ErrorMessage (Maybe T.Text)+    installTargetValidator = whenEmpty Nothing (Right . Just)++    toolVersionValidator :: T.Text -> Either Menu.ErrorMessage (Maybe TargetVersionReq)+    toolVersionValidator = whenEmpty Nothing (bimap T.pack Just . Utils.ghcVersionEither' . T.unpack)++    additionalValidator :: T.Text -> Either Menu.ErrorMessage [T.Text]+    additionalValidator = Right . T.split isSpace++    fields =+      [ Menu.createEditableField (Common.MenuElement Common.UrlEditBox) uriValidator instBindistL+          & Menu.fieldLabelL .~ "url"+          & Menu.fieldHelpMsgL .~ "Install the specified version from this bindist"+      , Menu.createCheckBoxField (Common.MenuElement Common.SetCheckBox) instSetL+          & Menu.fieldLabelL .~ "set"+          & Menu.fieldHelpMsgL .~ "Set as active version after install"+      , Menu.createEditableField (Common.MenuElement Common.ToolVersionBox) toolVersionValidator instVersionL+          & Menu.fieldLabelL .~ "version"+          & Menu.fieldHelpMsgL .~ "Specify a custom version"+      , Menu.createEditableField (Common.MenuElement Common.GHCInstallTargets) installTargetValidator installTargetsL+          & Menu.fieldLabelL .~ "install-targets"+          & Menu.fieldHelpMsgL .~ "Overwrite install targets (space separated list)"+      , Menu.createEditableField (Common.MenuElement Common.IsolateEditBox) filepathValidator isolateDirL+          & Menu.fieldLabelL .~ "isolated"+          & Menu.fieldHelpMsgL .~ "install in an isolated absolute directory instead of the default one"+      , Menu.createCheckBoxField (Common.MenuElement Common.ForceCheckBox) forceInstallL+          & Menu.fieldLabelL .~ "force"+          & Menu.fieldHelpMsgL .~ "Force install (THIS IS UNSAFE, only use it in Dockerfiles or CI)"+      , Menu.createEditableField (Common.MenuElement Common.AdditionalEditBox) additionalValidator addConfArgsL+          & Menu.fieldLabelL .~ "CONFIGURE_ARGS"+          & Menu.fieldHelpMsgL .~ "Additional arguments to bindist configure"+      ]++    ok = Menu.createButtonField (Common.MenuElement Common.OkButton)+          & Menu.fieldLabelL .~ "Advanced Install"+          & Menu.fieldHelpMsgL .~ "Install with options below"++handler :: BrickEvent Name e -> EventM Name AdvancedInstallMenu ()+handler = Menu.handlerMenu+++draw :: AdvancedInstallMenu -> [Widget Name]+draw = Menu.drawMenu
lib-tui/GHCup/Brick/Widgets/Menus/CompileGHC.hs view
@@ -61,7 +61,7 @@ import System.FilePath (isPathSeparator) import Control.Applicative (Alternative((<|>))) import Text.Read (readEither)-import qualified GHCup.Utils.Parsers as Utils+import qualified GHCup.Input.Parsers as Utils import           Text.PrettyPrint.HughesPJClass ( prettyShow )  data CompileGHCOptions = CompileGHCOptions@@ -78,7 +78,7 @@   , _buildSystem  :: Maybe BuildSystem   , _isolateDir   :: Maybe FilePath   , _gitRef       :: Maybe String-  , _installTargets :: T.Text+  , _installTargets :: Maybe T.Text   } deriving (Eq, Show)  makeLenses ''CompileGHCOptions@@ -88,7 +88,7 @@ create :: MenuKeyBindings -> [Version] -> CompileGHCMenu create k availableGHCs = Menu.createMenu CompileGHCBox initialState "Compile GHC" validator k buttons fields   where-    initialInstallTargets = "install"+    initialInstallTargets = Nothing     initialState =       CompileGHCOptions         (Right "")@@ -117,18 +117,18 @@      bootstrapV :: T.Text -> Either Menu.ErrorMessage (Either Version FilePath)     bootstrapV i =-      case not $ emptyEditor i of-        True  ->-          let readVersion = bimap (const "Not a valid version") Left (version i)-              readPath = do-                mfilepath <- filepathV i-                case mfilepath of-                  Nothing -> Left "Invalid path"-                  Just f  -> Right (Right f)-           in if T.any isPathSeparator i-                then readPath-                else readVersion-        False -> Left "No version selected / no path specified"+      if not $ emptyEditor i+      then+        let readVersion = bimap (const "Not a valid version") Left (version i)+            readPath = do+              mfilepath <- filepathV i+              case mfilepath of+                Nothing -> Left "Invalid path"+                Just f  -> Right (Right f)+         in if T.any isPathSeparator i+              then readPath+              else readVersion+      else Left "No version selected / no path specified"      hadrianstrapV :: T.Text -> Either Menu.ErrorMessage (Maybe (Either Version FilePath))     hadrianstrapV i' =@@ -161,6 +161,9 @@     additionalValidator :: T.Text -> Either Menu.ErrorMessage [T.Text]     additionalValidator = Right . T.split isSpace +    installTargetValidator :: T.Text -> Either Menu.ErrorMessage (Maybe T.Text)+    installTargetValidator = whenEmpty Nothing (Right . Just)+     showMaybeBuildSystem :: Maybe BuildSystem -> T.Text     showMaybeBuildSystem  = \case       Nothing -> "Auto select (prefer hadrian if available, and build config is not specified)"@@ -169,7 +172,7 @@      bootstrapGHCFields = case NE.nonEmpty availableGHCs of         Just ne ->-          let bootstrapGhc' = bootstrapGhc % (iso (either (Left . Left) (Left . Right)) (either id Left))+          let bootstrapGhc' = bootstrapGhc % iso (either (Left . Left) (Left . Right)) (either id Left)           in [ Menu.createSelectFieldWithEditable (Common.MenuElement Common.BootstrapGhcSelectBox) (Common.MenuElement Common.BootstrapGhcEditBox) bootstrapGhc' bootstrapV ne (T.pack . prettyShow) k                & Menu.fieldLabelL .~ "bootstrap-ghc"                & Menu.fieldHelpMsgL .~ "The GHC version (or full path) to bootstrap with (must be installed)"@@ -183,7 +186,7 @@      hadrianGHCFields = case NE.nonEmpty availableGHCs of         Just ne ->-          let hadrianGhc' = hadrianGhc % (iso Left (either id (Just . Left)))+          let hadrianGhc' = hadrianGhc % iso Left (either id (Just . Left))           in [ Menu.createSelectFieldWithEditable (Common.MenuElement Common.HadrianGhcSelectBox) (Common.MenuElement Common.HadrianGhcEditBox) hadrianGhc' hadrianstrapV ne (T.pack . prettyShow) k                & Menu.fieldLabelL .~ "hadrian-ghc"                & Menu.fieldHelpMsgL .~ "The GHC version (or full path) that will be used to compile hadrian (must be installed)"@@ -205,17 +208,17 @@           & Menu.fieldHelpMsgL .~ "Set the compile build flavour (this value depends on the build system type: 'make' vs 'hadrian')"       , Menu.createEditableField (Common.MenuElement Common.AdditionalEditBox) additionalValidator addConfArgs           & Menu.fieldLabelL .~ "CONFIGURE_ARGS"-          & Menu.fieldHelpMsgL .~ "Additional arguments to compile configure"+          & Menu.fieldHelpMsgL .~ "Additional arguments to bindist configure"       , Menu.createEditableField (Common.MenuElement Common.BuildConfigEditBox) filepathV buildConfig           & Menu.fieldLabelL .~ "build config"           & Menu.fieldHelpMsgL .~ "Absolute path to build config file (make build system only)"       , Menu.createEditableField (Common.MenuElement Common.PatchesEditBox) patchesV patches           & Menu.fieldLabelL .~ "patches"-          & Menu.fieldHelpMsgL .~ "Either a URI to a patch (https/http/file) or Absolute path to patch directory"+          & Menu.fieldHelpMsgL .~ "Either a URI to a patch (https/http/file) or absolute path to patch directory"       , Menu.createEditableField (Common.MenuElement Common.CrossTargetEditBox) (Right . Just) crossTarget           & Menu.fieldLabelL .~ "cross target"           & Menu.fieldHelpMsgL .~ "Build cross-compiler for this platform"-      , Menu.createSelectField (Common.MenuElement Common.BuildSystemEditBox) (buildSystem % (iso Just join)) (Nothing :| [Just Hadrian, Just Make]) showMaybeBuildSystem  k+      , Menu.createSelectField (Common.MenuElement Common.BuildSystemEditBox) (buildSystem % iso Just join) (Nothing :| [Just Hadrian, Just Make]) showMaybeBuildSystem  k           & Menu.fieldLabelL .~ "build system"           & Menu.fieldHelpMsgL .~ "Select the build system"       , Menu.createEditableField (Common.MenuElement Common.OvewrwiteVerEditBox) versionV overwriteVer@@ -223,13 +226,13 @@           & Menu.fieldHelpMsgL .~ "Allows to overwrite the finally installed VERSION with a different one. Allows to specify patterns: %v (version), %b (branch name), %h (short commit hash), %H (long commit hash), %g ('git describe' output)"       , Menu.createEditableField (Common.MenuElement Common.IsolateEditBox) filepathV isolateDir           & Menu.fieldLabelL .~ "isolated"-          & Menu.fieldHelpMsgL .~ "install in an isolated absolute directory instead of the default one"+          & Menu.fieldHelpMsgL .~ "Install in an isolated absolute directory instead of the default one"       , Menu.createEditableField (Common.MenuElement Common.GitRefEditBox) (Right . Just . T.unpack) gitRef           & Menu.fieldLabelL .~ "git-ref"           & Menu.fieldHelpMsgL .~ "The git commit/branch/ref to build from"-      , Menu.createEditableField' initialInstallTargets (Common.MenuElement Common.GHCInstallTargets) Right installTargets+      , Menu.createEditableField (Common.MenuElement Common.GHCInstallTargets) installTargetValidator installTargets           & Menu.fieldLabelL .~ "install-targets"-          & Menu.fieldHelpMsgL .~ "Specify space separated list of make install targets"+          & Menu.fieldHelpMsgL .~ "Overwrite install targets (space separated list)"       ]      buttons = [
lib-tui/GHCup/Brick/Widgets/Menus/CompileHLS.hs view
@@ -44,7 +44,7 @@ import           Prelude                 hiding ( appendFile ) import           Optics.TH (makeLenses) import qualified GHCup.Brick.Common as Common-import GHCup.Types (VersionPattern, ToolVersion(..))+import GHCup.Types (VersionPattern, ToolVersion(..), VersionReq(..)) import URI.ByteString (URI) import qualified Data.Text as T import Data.Bifunctor (Bifunctor(..))@@ -55,7 +55,7 @@ import Data.Versions import Control.Applicative (Alternative((<|>))) import Text.Read (readEither)-import qualified GHCup.Utils.Parsers as Utils+import qualified GHCup.Input.Parsers as Utils import           Text.PrettyPrint.HughesPJClass ( prettyShow )  data CompileHLSOptions = CompileHLSOptions@@ -145,7 +145,7 @@      targetGHCsField =       let label = "target GHC(s)"-      in case NE.nonEmpty (fmap ToolVersion availableGHCs) of+      in case NE.nonEmpty (fmap (ToolVersion . (`VersionReq` Nothing)) availableGHCs) of         Just ne -> Menu.createMultiSelectField (Common.MenuElement Common.TargetGhcEditBox) targetGHCs ne (T.pack . prettyShow) k             & Menu.fieldLabelL .~ label             & Menu.fieldHelpMsgL .~ "GHC versions to compile for (Press Enter to edit)"
lib-tui/GHCup/Brick/Widgets/Menus/Context.hs view
@@ -9,8 +9,8 @@ import Prelude hiding (appendFile)  import Data.Versions (prettyVer)-import GHCup.List ( ListResult(..) )-import GHCup.Types (Tool (..))+import GHCup.Command.List ( ListResult(..) )+import GHCup.Types (Tool (..), ToolDescription(..))  import qualified GHCup.Brick.Common as Common import qualified GHCup.Brick.Widgets.Menu as Menu@@ -21,20 +21,21 @@ import qualified Brick.Focus as F import Brick.Widgets.Core ((<+>)) -import Optics (to)+import Optics (to, _1, _2) import Optics.Operators ((.~), (^.)) import Optics.Optic ((%)) import Data.Foldable (foldl')+import qualified Data.Text as T -type ContextMenu = Menu ListResult Name+type ContextMenu = Menu (Tool, (Maybe ToolDescription, ListResult)) Name -create :: ListResult -> MenuKeyBindings -> ContextMenu-create lr keyBindings = Menu.createMenu Common.ContextBox lr "" validator keyBindings buttons []+create :: (Tool, (Maybe ToolDescription, ListResult)) -> MenuKeyBindings -> ContextMenu+create (tool, (td, lr)) keyBindings = Menu.createMenu Common.ContextBox (tool, (td, lr)) "" validator keyBindings buttons []  where   advInstallButton =-    Menu.createButtonField (MenuElement Common.AdvanceInstallButton)+    Menu.createButtonField (MenuElement Common.AdvancedInstallButton)       & Menu.fieldLabelL .~ "Install"-      & Menu.fieldHelpMsgL .~ "Advance Installation Settings"+      & Menu.fieldHelpMsgL .~ "Advanced Installation Settings"   compileGhcButton =     Menu.createButtonField (MenuElement Common.CompileGHCButton)       & Menu.fieldLabelL .~ "Compile"@@ -44,16 +45,16 @@       & Menu.fieldLabelL .~ "Compile"       & Menu.fieldHelpMsgL .~ "Compile HLS from source"   buttons =-    case lTool lr of-      GHC -> [advInstallButton, compileGhcButton]-      HLS -> [advInstallButton, compileHLSButton]+    case tool of+      Tool "ghc" -> [advInstallButton, compileGhcButton]+      Tool "hls" -> [advInstallButton, compileHLSButton]       _ -> [advInstallButton]   validator = const Nothing  draw :: ContextMenu -> Widget Name draw menu =   Common.frontwardLayer-    ("Context Menu for " <> tool_str <> " " <> prettyVer (lVer $ menu ^. Menu.menuStateL))+    ("Context Menu for " <> tool_str <> " " <> prettyVer (menu ^. Menu.menuStateL % _2 % _2 % to lVer))     $ Brick.vBox         [ Brick.vBox buttonWidgets         , Brick.txt " "@@ -72,12 +73,13 @@     drawButtons = fmap Menu.drawField buttonAmplifiers     buttonWidgets = zipWith (F.withFocusRing (menu ^. Menu.menuFocusRingL)) drawButtons (menu ^. Menu.menuButtonsL)     tool_str =-      case menu ^. Menu.menuStateL % to lTool of-        GHC -> "GHC"-        GHCup -> "GHCup"-        Cabal -> "Cabal"-        HLS -> "HLS"-        Stack -> "Stack"+      case menu ^. Menu.menuStateL % _1 of+        Tool "ghc" -> "GHC"+        Tool "ghcup" -> "GHCup"+        Tool "cabal" -> "Cabal"+        Tool "hls" -> "HLS"+        Tool "stack" -> "Stack"+        Tool t -> T.pack t  handler :: BrickEvent Name e -> EventM Name ContextMenu () handler = Menu.handlerMenu
lib-tui/GHCup/Brick/Widgets/Navigation.hs view
@@ -7,26 +7,19 @@ {-# OPTIONS_GHC -Wno-unused-matches #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-}--{- Brick's navigation widget:-It is a FocusRing over many list's. Each list contains the information for each tool. Each list has an internal name (for Brick's runtime)-and a label which we can use in rendering. This data-structure helps to reuse Brick.Widget.List and to navegate easily across---}-+{-# LANGUAGE ViewPatterns #-} -module GHCup.Brick.Widgets.Navigation (BrickInternalState, create, handler, draw) where+module GHCup.Brick.Widgets.Navigation (BrickInternalState, handler, draw) where -import GHCup.List ( ListResult(..) )+import GHCup.Command.List ( ListResult(..), RevTag(..) ) import GHCup.Types-    ( GHCTargetVersion(GHCTargetVersion),+    ( TargetVersion(TargetVersion),       Tool(..),       Tag(..),       tVerToText,-      tagToString )+      tagToString, ToolDescription ) import qualified GHCup.Brick.Common as Common import qualified GHCup.Brick.Attributes as Attributes-import qualified GHCup.Brick.Widgets.SectionList as SectionList import Brick     ( BrickEvent(..),       Padding(Max, Pad),@@ -36,78 +29,116 @@       (<+>),       (<=>)) import qualified Brick-import           Brick.Widgets.Border ( hBorder, borderWithLabel)+import           Brick.Widgets.Border ( hBorder, borderWithLabel, vBorder) import           Brick.Widgets.Border.Style ( unicode ) import           Brick.Widgets.Center ( center ) import qualified Brick.Widgets.List as L import           Data.List ( intercalate, sort ) import           Data.Maybe ( mapMaybe )-import           Data.Vector ( Vector) import           Data.Versions ( prettyPVP, prettyVer ) import           Prelude                 hiding ( appendFile ) import qualified Data.Text                     as T import qualified Data.Vector                   as V-+import Text.PrettyPrint.HughesPJClass (prettyShow)+import Control.Monad.State.Class (get, modify)+import qualified Graphics.Vty           as Vty -type BrickInternalState = SectionList.SectionList Common.Name ListResult+type BrickList = L.GenericList Common.Name V.Vector --- | How to create a navigation widget-create :: Common.Name                         -- The name of the section list-       -> [(Common.Name, Vector ListResult)]  -- a list of tuples (section name, collection of elements)-       -> Int                                 -- The height of each item in a list. Commonly 1-       -> BrickInternalState-create = SectionList.sectionList+type BrickInternalState = BrickList (Tool, (Maybe ToolDescription, BrickList ListResult))  -- | How the navigation handler handle events-handler :: BrickEvent Common.Name e -> EventM Common.Name BrickInternalState ()-handler = SectionList.handleGenericListEvent+handler :: Bool -> BrickEvent Common.Name e -> EventM Common.Name BrickInternalState ()+handler False (Brick.VtyEvent e) = L.handleListEvent e+handler True (Brick.VtyEvent e) = do+  bis :: BrickInternalState <- get+  case L.listSelectedElement bis of+    Nothing -> pure ()+    Just (_, (t, (td, vlr))) -> do+      updatedVlr <- Brick.nestEventM' vlr (handleVersionEvent e)+      modify (L.listModify $ (fmap . fmap) (const updatedVlr))+ where+  -- need to reverse because we reversed the list+  handleVersionEvent (Vty.EvKey Vty.KUp [])   = L.handleListEvent (Vty.EvKey Vty.KDown [])+  handleVersionEvent (Vty.EvKey Vty.KDown []) = L.handleListEvent (Vty.EvKey Vty.KUp [])+  handleVersionEvent (Vty.EvKey Vty.KPageDown [])   = L.handleListEvent (Vty.EvKey Vty.KPageUp [])+  handleVersionEvent (Vty.EvKey Vty.KPageUp [])   = L.handleListEvent (Vty.EvKey Vty.KPageDown [])+  handleVersionEvent (Vty.EvKey Vty.KHome [])   = L.handleListEvent (Vty.EvKey Vty.KEnd [])+  handleVersionEvent (Vty.EvKey Vty.KEnd [])   = L.handleListEvent (Vty.EvKey Vty.KHome [])+  handleVersionEvent e' = L.handleListEvent e'+handler _ _ = pure () + -- | How to draw the navigation widget-draw :: AttrMap -> BrickInternalState -> Widget Common.Name-draw dimAttrs section_list+draw :: Bool -> AttrMap -> BrickInternalState -> Widget Common.Name+draw versionFocus dimAttrs bis   = Brick.padBottom Max-      ( Brick.withBorderStyle unicode+      ( Brick.joinBorders $ Brick.withBorderStyle unicode         $ borderWithLabel (Brick.str "GHCup")-          (center (header <=> hBorder <=> renderList' section_list))+          (center (Brick.vLimit 1 header <=> hBorder <=> renderList'))       )  where+  minHSize s' = Brick.hLimit s' . Brick.vLimit 1 . (<+> Brick.fill ' ')+  allElements = L.listElements bis+  minToolSize = V.maximum $ V.map (length . prettyShow . fst) allElements+  selectedTool = fmap snd $ L.listSelectedElement bis+  minTagSize = maybe 0 (\(t, (_, vlr)) -> V.maximum $ V.map (length . intercalate "," . fmap tagToString . lTag) $ L.listElements vlr) selectedTool+  minVerSizeList = maybe 0 (\(t, (_, vlr)) ->  V.maximum $ V.map (\ListResult{..} -> T.length $ tVerToText (TargetVersion lCross lVer)) $ L.listElements vlr) selectedTool+  minVerHeaderSize = length $ maybe "Versions" (\(fst -> t) -> prettyShow t <> " versions") selectedTool+  minVerSize = max minVerSizeList minVerHeaderSize   header =-    minHSize 2 Brick.emptyWidget-      <+> Brick.padLeft (Pad 2) (minHSize 6 $ Brick.str "Tool")-      <+> minHSize 15 (Brick.str "Version")-      <+> Brick.padLeft (Pad 1) (minHSize 25 $ Brick.str "Tags")+      Brick.padLeft (Pad 1) (minHSize (minToolSize + 2) (Brick.str "Tool"))+      <+> vBorder+      <+> Brick.padLeft (Pad 1) (minHSize (minVerSize + 2) (maybe (Brick.str "Versions") (\(fst -> t) -> printTool t <+> Brick.str " versions") selectedTool))+      <+> Brick.padLeft (Pad 2) (minHSize minTagSize (Brick.str "Tags"))       <+> Brick.padLeft (Pad 5) (Brick.str "Notes")-  renderList' bis =-    let allElements = V.concatMap L.listElements $ SectionList.sectionListElements bis-        minTagSize = V.maximum $ V.map (length . intercalate "," . fmap tagToString . lTag) allElements-        minVerSize = V.maximum $ V.map (\ListResult{..} -> T.length $ tVerToText (GHCTargetVersion lCross lVer)) allElements-    in Brick.withDefAttr L.listAttr $ SectionList.renderSectionList (renderItem minTagSize minVerSize) True bis-  renderItem minTagSize minVerSize listIx b listResult@ListResult{lTag = lTag', ..} =++  renderList' =+    let toolColumn = Brick.hLimit (minToolSize + 2)+          (Brick.withDefAttr L.listAttr (L.renderList renderTool (not versionFocus) bis))+        versionColumn = maybe Brick.emptyWidget+          (\(t, (_, vlr)) ->+            Brick.withDefAttr L.listAttr+                $ L.renderListWithIndex (renderItem t) versionFocus+                $ L.listReverse vlr+          )+          selectedTool+    in Brick.padLeft (Pad 1) toolColumn+       <+> vBorder+       <+> Brick.padLeft (Pad 1) versionColumn++  renderTool :: Bool -> (Tool, (Maybe ToolDescription, BrickList ListResult)) -> Widget Common.Name+  renderTool b (t, (tDesc, _)) = minHSize minToolSize $ printTool t++  renderItem t listIx b listResult@ListResult{lTag = lTag', ..} =     let marks = if           | lSet       -> (Brick.withAttr Attributes.setAttr $ Brick.str Common.setSign)           | lInstalled -> (Brick.withAttr Attributes.installedAttr $ Brick.str Common.installedSign)           | otherwise  -> (Brick.withAttr Attributes.notInstalledAttr $ Brick.str Common.notInstalledSign)+        rev = case lRev of+                (rev', RevUpdate)   -> "-r" <> show rev'+                (rev', RevOutdated) -> "-r" <> show rev'+                (_,    RevNormal)   -> ""         ver = case lCross of-          Nothing -> T.unpack . prettyVer $ lVer-          Just c  -> T.unpack (c <> "-" <> prettyVer lVer)+          Nothing -> T.unpack (prettyVer lVer) <> rev+          Just c  -> T.unpack (c <> "-" <> prettyVer lVer) <> rev         dim           | lNoBindist && not lInstalled-            && not b -- TODO: overloading dim and active ignores active-                       --       so we hack around it here+            && (  not versionFocus -- TODO: overloading dim and active ignores active+               || not b             -- so we hack around it here+               )           = Brick.updateAttrMap (const dimAttrs) . Brick.withAttr (Brick.attrName "no-bindist")           | otherwise  = id         hooray-          | elem Latest lTag' && not lInstalled =+          | elem Latest lTag' && not lInstalled && not lNoBindist =               Brick.withAttr Attributes.hoorayAttr+          | (_, RevUpdate) <- lRev+          = Brick.withAttr Attributes.hoorayAttr           | otherwise = id-        active = if b then Common.enableScreenReader (Common.ListItem lTool listIx) else id-    in Brick.clickable (Common.ListItem lTool listIx) $ hooray $ active $ dim+        active = if b then Common.enableScreenReader (Common.ListItem t listIx) else id+    in Brick.clickable (Common.ListItem t listIx) $ hooray $ active $ dim           (   marks-          <+> Brick.padLeft (Pad 2)-               ( minHSize 6-                 (printTool lTool)-               )-          <+> minHSize minVerSize (Brick.str ver)+          <+> Brick.padLeft (Pad 1) (minHSize minVerSize (Brick.str ver))           <+> (let l = mapMaybe printTag $ sort lTag'                in  Brick.padLeft (Pad 1) $ minHSize minTagSize $ if null l                      then Brick.emptyWidget@@ -133,11 +164,12 @@   printTag Experimental     = Just $ Brick.withAttr Attributes.latestNightlyAttr $ Brick.str "experimental"   printTag (UnknownTag t) = Just $ Brick.str t -  printTool Cabal = Brick.str "cabal"-  printTool GHC = Brick.str "GHC"-  printTool GHCup = Brick.str "GHCup"-  printTool HLS = Brick.str "HLS"-  printTool Stack = Brick.str "Stack"+  printTool (Tool "cabal") = Brick.str "cabal"+  printTool (Tool "ghc") = Brick.str "GHC"+  printTool (Tool "ghcup") = Brick.str "GHCup"+  printTool (Tool "hls") = Brick.str "HLS"+  printTool (Tool "stack") = Brick.str "Stack"+  printTool (Tool t) = Brick.str t    printNotes ListResult {..} =     (if hlsPowered then [Brick.withAttr Attributes.hlsPoweredAttr $ Brick.str "hls-powered"] else mempty@@ -147,9 +179,3 @@             Nothing -> mempty             Just d  -> [Brick.withAttr Attributes.dayAttr $ Brick.str (show d)]) -  minHSize s' = Brick.hLimit s' . Brick.vLimit 1 . (<+> Brick.fill ' ')--instance SectionList.ListItemSectionNameIndex Common.Name where-  getListItemSectionNameIndex = \case-    Common.ListItem tool ix -> Just (Common.Singular tool, ix)-    _ -> Nothing
− lib-tui/GHCup/Brick/Widgets/SectionList.hs
@@ -1,206 +0,0 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TypeApplications  #-}-{-# LANGUAGE RankNTypes        #-}-{-# LANGUAGE ViewPatterns      #-}-{-# OPTIONS_GHC -Wno-unused-record-wildcards #-}-{-# OPTIONS_GHC -Wno-unused-matches #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TemplateHaskell   #-}-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE InstanceSigs #-}--{- A general system for lists with sections--Consider this code as private. GenericSectionList should not be used directly as the FocusRing should be align with the Vector containing-the elements, otherwise you'd be focusing on a non-existent widget with unknown result (In theory the code is safe unless you have an empty section list).--- To build a SectionList use the safe constructor sectionList-- To access sections use the lens provider sectionL and the name of the section you'd like to access-- You can modify Brick.Widget.List.GenericList within GenericSectionList via sectionL but do not-  modify the vector length---}---module GHCup.Brick.Widgets.SectionList where---import Brick-    ( BrickEvent(VtyEvent, MouseDown),-      EventM,-      Size(..),-      Widget(..),-      ViewportType (Vertical),-      (<=>))-import qualified Brick-import           Brick.Widgets.Border ( hBorder)-import qualified Brick.Widgets.List as L-import           Brick.Focus (FocusRing)-import qualified Brick.Focus as F-import           Data.Function ( (&))-import Data.Maybe ( fromMaybe )-import           Data.Vector ( Vector )-import qualified GHCup.Brick.Common as Common-import           Prelude                 hiding ( appendFile )--import qualified Graphics.Vty                  as Vty-import qualified Data.Vector                   as V--import           Optics.TH (makeLensesFor)-import           Optics.State (use)-import           Optics.State.Operators ( (%=), (<%=))-import           Optics.Operators ((.~), (^.))-import           Optics.Lens (Lens', lens)--data GenericSectionList n t e-    = GenericSectionList-    { sectionListFocusRing :: FocusRing n                   -- ^ The FocusRing for all sections-    , sectionListElements :: !(Vector (L.GenericList n t e)) -- ^ A vector of brick's built-in list-    , sectionListName :: n                                   -- ^ The section list name-    }--makeLensesFor [("sectionListFocusRing", "sectionListFocusRingL"), ("sectionListElements", "sectionListElementsL"), ("sectionListName", "sectionListNameL")] ''GenericSectionList--type SectionList n e = GenericSectionList n V.Vector e---- | To support selection by mouse click we need to obtain section name and item--- index from the name of the item that got clicked. This helper class is to get that-class ListItemSectionNameIndex n where-  getListItemSectionNameIndex :: n -> Maybe (n, Int)---- | Build a SectionList from nonempty list. If empty we could not defined sectionL lenses.-sectionList :: Foldable t-            => n                     -- The name of the section list-            -> [(n, t e)]            -- a list of tuples (section name, collection of elements)-            -> Int-            -> GenericSectionList n t e-sectionList name elements height-  = GenericSectionList-  { sectionListFocusRing = F.focusRing [section_name | (section_name, _) <- elements]-  , sectionListElements  = V.fromList [L.list section_name els height | (section_name, els) <- elements]-  , sectionListName = name-  }--- | This lens constructor, takes a name and looks if a section has such a name.---   Used to dispatch events to sections. It is a partial function only meant to---   be used with the FocusRing inside GenericSectionList-sectionL :: Eq n => n -> Lens' (GenericSectionList n t e) (L.GenericList n t e)-sectionL section_name = lens g s-    where is_section_name = (== section_name) . L.listName-          g section_list =-            let elms   = section_list ^. sectionListElementsL-                zeroth = elms V.! 0 -- TODO: This crashes for empty vectors.-            in fromMaybe zeroth (V.find is_section_name elms)-          s gl@(GenericSectionList _ elms _) list =-            case V.findIndex is_section_name elms of-                 Nothing -> gl-                 Just i  -> let new_elms = V.update elms (V.fromList [(i, list)])-                             in gl & sectionListElementsL .~ new_elms--moveDown :: (L.Splittable t, Ord n, Foldable t) => EventM n (GenericSectionList n t e) ()-moveDown = do-    ring <- use sectionListFocusRingL-    case F.focusGetCurrent ring of-        Nothing -> pure ()-        Just l  -> do      -- If it is the last element, move to the first element of the next focus; else, just handle regular list event.-            current_list <- use (sectionL l)-            let current_idx = L.listSelected current_list-                list_length = current_list & length-            if current_idx == Just (list_length - 1)-                then do-                    new_focus <- sectionListFocusRingL <%= F.focusNext-                    case F.focusGetCurrent new_focus of-                        Nothing -> pure () -- |- Optic.Zoom.zoom doesn't typecheck but Lens.Micro.Mtl.zoom does. It is re-exported by Brick-                        Just new_l -> Common.zoom (sectionL new_l) (Brick.modify L.listMoveToBeginning)-                else Common.zoom  (sectionL l) $ Brick.modify L.listMoveDown--moveUp :: (L.Splittable t, Ord n, Foldable t) => EventM n (GenericSectionList n t e) ()-moveUp = do-    ring <- use sectionListFocusRingL-    case F.focusGetCurrent ring of-        Nothing -> pure ()-        Just l  -> do  -- If it is the first element, move to the last element of the prev focus; else, just handle regular list event.-            current_list <- use (sectionL l)-            let current_idx = L.listSelected current_list-            if current_idx == Just 0-                then do-                    new_focus <- sectionListFocusRingL <%= F.focusPrev-                    case F.focusGetCurrent new_focus of-                        Nothing -> pure ()-                        Just new_l -> Common.zoom (sectionL new_l) (Brick.modify L.listMoveToEnd)-                else Common.zoom (sectionL l) $ Brick.modify L.listMoveUp--sectionListSelectItem :: (L.Splittable t, Eq n, ListItemSectionNameIndex n, Foldable t) => n -> EventM n (GenericSectionList n t e) ()-sectionListSelectItem selectedItem = case getListItemSectionNameIndex selectedItem of-  Nothing -> pure ()-  Just (secName, ix) -> do-    sectionListFocusRingL %= F.focusSetCurrent secName-    Common.zoom (sectionL secName) (Brick.modify $ L.listMoveTo ix)---- | Handle events for list cursor movement.  Events handled are:------ * Up (up arrow key). If first element of section, then jump prev section--- * Down (down arrow key). If last element of section, then jump next section--- * Page Up (PgUp)--- * Page Down (PgDown)--- * Go to next section (Tab)--- * Go to prev section (BackTab)--- * Select an element via Mouse left click-handleGenericListEvent :: (Foldable t, L.Splittable t, Ord n, ListItemSectionNameIndex n)-                       => BrickEvent n a-                       -> EventM n (GenericSectionList n t e) ()-handleGenericListEvent (VtyEvent (Vty.EvResize _ _))              = pure ()-handleGenericListEvent (VtyEvent (Vty.EvKey (Vty.KChar '\t') [])) = sectionListFocusRingL %= F.focusNext-handleGenericListEvent (VtyEvent (Vty.EvKey Vty.KBackTab []))     = sectionListFocusRingL %= F.focusPrev-handleGenericListEvent (MouseDown n Vty.BLeft _ _)                = sectionListSelectItem n-handleGenericListEvent (MouseDown _ Vty.BScrollDown _ _)          = moveDown-handleGenericListEvent (MouseDown _ Vty.BScrollUp _ _)            = moveUp-handleGenericListEvent (VtyEvent (Vty.EvKey Vty.KDown []))        = moveDown-handleGenericListEvent (VtyEvent (Vty.EvKey Vty.KUp []))          = moveUp-handleGenericListEvent (VtyEvent ev) = do-    ring <- use sectionListFocusRingL-    case F.focusGetCurrent ring of-        Nothing -> pure ()-        Just l  -> Common.zoom (sectionL l) $ L.handleListEvent ev-handleGenericListEvent _ = pure ()---- This re-uses Brick.Widget.List.renderList-renderSectionList :: forall n t e . (Traversable t, Ord n, Show n, Eq n, L.Splittable t, Semigroup (t e))-                  => (Int -> Bool -> e -> Widget n)      -- ^ Rendering function of the list element, True for the selected element-                  -> Bool                                -- ^ Whether the section list has focus-                  -> GenericSectionList n t e            -- ^ The section list to render-                  -> Widget n-renderSectionList renderElem sectionFocus ge@(GenericSectionList focus elms slName) =-    Brick.Widget Brick.Greedy Brick.Greedy $ Brick.render $ Brick.viewport slName Brick.Vertical $-      V.ifoldl' (\(!accWidget) !i list ->-                      let hasFocusList = sectionIsFocused list-                          makeVisible = if hasFocusList then Brick.visibleRegion (Brick.Location (c, r)) (1, 1) else id-                          appendBorder = if i == 0 then id else (hBorder <=>)-                          newWidget = appendBorder (makeVisible $ renderInnerList hasFocusList list)-                      in accWidget <=> newWidget-                      )-      Brick.emptyWidget-      elms- where-  -- A section is focused if the whole thing is focused, and the inner list has focus-  sectionIsFocused :: L.GenericList n t e -> Bool-  sectionIsFocused l = sectionFocus && (Just (L.listName l) == F.focusGetCurrent focus)--  renderInnerList :: Bool -> L.GenericList n t e -> Widget n-  renderInnerList hasFocus l = Brick.vLimit (length l) $ L.renderListWithIndex (\i b -> renderElem i (b && hasFocus)) hasFocus l--  -- compute the location to focus on within the active section-  (c, r) :: (Int, Int) = case sectionListSelectedElement ge of-                           Nothing -> (0, 0)-                           Just (selElIx, _) -> (0, selElIx)----- | Equivalent to listSelectedElement-sectionListSelectedElement :: (Eq n, L.Splittable t, Traversable t, Semigroup (t e)) => GenericSectionList n t e -> Maybe (Int, e)-sectionListSelectedElement generic_section_list = do-  current_focus <- generic_section_list ^. sectionListFocusRingL & F.focusGetCurrent-  let current_section = generic_section_list ^. sectionL current_focus-  L.listSelectedElement current_section
+ lib-tui/GHCup/Brick/Widgets/ToolInfo.hs view
@@ -0,0 +1,108 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# OPTIONS_GHC -Wno-unused-record-wildcards #-}+{-# OPTIONS_GHC -Wno-unused-matches #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ViewPatterns #-}++module GHCup.Brick.Widgets.ToolInfo where++import GHCup.Brick.Widgets.Navigation ( BrickInternalState )+import GHCup.Prelude                  ( decUTF8Safe )+import GHCup.Types                    ( KeyBindings (..) )+import GHCup.Types.Optics++import qualified GHCup.Brick.Common as Common++import Brick+    ( Padding (Max), Widget (..), (<+>), (<=>) )+import Brick.Widgets.Center           ( center )+import Data.Maybe                     ( fromMaybe )+import Optics                         ( to, (%), (^.) )+import Prelude                        hiding ( appendFile )+import Text.PrettyPrint.HughesPJClass ( prettyShow )+import URI.ByteString                 ( serializeURIRef' )++import qualified Brick+import qualified Brick.Widgets.List as L+import qualified Data.Text          as T+++mkTextBox :: [Widget Common.Name] -> Widget Common.Name+mkTextBox = Brick.hLimitPercent 70 . Brick.vBox . fmap (Brick.padRight Brick.Max)++draw :: BrickInternalState -> KeyBindings -> Widget Common.Name+draw (L.listSelectedElement -> (Just (_, (tool, (Just td, _))))) (KeyBindings {..}) =+  Common.frontwardLayer (T.pack (prettyShow tool) <> " details")+      $ Brick.vBox [+        center $ Brick.hLimitPercent 70 $+         (Brick.vBox . fmap (Brick.padRight (Brick.Pad 2))) [+            Brick.hBox [+              Brick.txt "Description: "+            ],+            Brick.hBox [+              Brick.txt "Homepage: "+            ],+            Brick.hBox [+              Brick.txt "Repository: "+            ],+            Brick.hBox [+              Brick.txt "Author: "+            ],+            Brick.hBox [+              Brick.txt "Maintainer: "+            ],+            Brick.hBox [+              Brick.txt "Contact: "+            ],+            Brick.hBox [+              Brick.txt "License: "+            ]+          ]+          <+>+         (Brick.vBox . fmap (Brick.padRight Brick.Max)) [+            Brick.hBox [+              Brick.txt (td ^. toolDescription)+            ],+            Brick.hBox [+              td ^. toolHomepage % to maybeURI+            ],+            Brick.hBox [+              td ^. toolRepository % to maybeURI+            ],+            Brick.hBox [+              Brick.txt (td ^. toolAuthor % to maybeString)+            ],+            Brick.hBox [+              Brick.txt (td ^. toolMaintainer % to maybeString)+            ],+            Brick.hBox [+              Brick.txt (td ^. toolContact % to maybeString)+            ],+            Brick.hBox [+              Brick.txt (td ^. toolLicense % to maybeString)+            ]+          ]+        ]+      <=> Brick.hBox [Brick.txt "Press " <+> Common.keyToWidget bQuit <+> Brick.txt " to return to Navigation"]+ where+  maybeString = T.pack . fromMaybe "-- Not specified --"+  maybeURI = maybe (Brick.txt "-- Not specified --")+               (\url -> let link = decUTF8Safe . serializeURIRef' $ url+                         in Brick.hyperlink link . Brick.txt $ link+               )+draw _ (KeyBindings {..}) =+  Common.frontwardLayer "Tool details"+      $ Brick.vBox [+        center $+         mkTextBox [+            Brick.hBox [+              Brick.txt "No details available"+            ]+          ]+        ] <=>+    Brick.hBox [Brick.txt "Press " <+> Common.keyToWidget bQuit <+> Brick.txt " to return to Navigation"]
lib-tui/GHCup/Brick/Widgets/Tutorial.hs view
@@ -42,12 +42,12 @@                 Brick.hBox [                   Brick.txt "This symbol "                 , Brick.withAttr Attributes.installedAttr (Brick.str Common.installedSign)-                , Brick.txtWrap " means that the tool is installed but not in used"+                , Brick.txtWrap " means that the tool is installed but not in use"                 ]               , Brick.hBox [                   Brick.txt "This symbol "                 , Brick.withAttr Attributes.setAttr (Brick.str Common.setSign)-                , Brick.txtWrap " means that the tool is installed and in used"+                , Brick.txtWrap " means that the tool is installed and in use"                 ]               , Brick.hBox [                   Brick.txt "This symbol "@@ -59,7 +59,7 @@             , mkTextBox [                 Brick.hBox [                   Brick.withAttr Attributes.recommendedAttr $ Brick.str "recommended"-                , Brick.txtWrap " tag is based on community adoption, known bugs, etc... So It makes this version the least experimental"+                , Brick.txtWrap " tag is based on community adoption, known bugs, etc... So it makes this version the least experimental"                 ]               , Brick.hBox [                   Brick.withAttr Attributes.latestAttr $ Brick.str "latest"@@ -71,9 +71,8 @@                 , Brick.withAttr Attributes.setAttr (Brick.str Common.setSign)                 , Brick.txt ") hls"                 ]-              , Brick.txtWrap "base-X.Y.Z.W tag is the minimun version of the base package admited in such ghc version"+              , Brick.txtWrap "base-X.Y.Z.W tag is the minimum version of the base package admitted in such ghc version"               ]             , Brick.txt " "             ])-        <=> (Brick.padRight Brick.Max $-          Brick.txt "Press " <+> Common.keyToWidget exitKey <+> Brick.txt " to exit the tutorial")+        <=> Brick.padRight Brick.Max ( Brick.txt "Press " <+> Common.keyToWidget exitKey <+> Brick.txt " to exit the tutorial")
lib-tui/GHCup/BrickMain.hs view
@@ -15,10 +15,10 @@  module GHCup.BrickMain where -import GHCup.List ( ListResult (..))+import GHCup.Command.List ( ListResult (..)) import GHCup.Types-    ( Settings(noColor), Tool (GHC),-      AppState(ghcupInfo, settings, keyBindings, loggerConfig), KeyBindings(..) )+    ( Settings(noColor),+      AppState(ghcupInfo, settings, keyBindings, loggerConfig), KeyBindings(..), Tool(..) ) import GHCup.Prelude.Logger ( logError ) import qualified GHCup.Brick.Actions as Actions import qualified GHCup.Brick.Common as Common@@ -26,12 +26,11 @@ import qualified GHCup.Brick.Attributes as Attributes import qualified GHCup.Brick.BrickState as AppState import qualified GHCup.Brick.Widgets.Menus.Context as ContextMenu-import qualified GHCup.Brick.Widgets.SectionList as Navigation-import qualified GHCup.Brick.Widgets.Menus.AdvanceInstall as AdvanceInstall+import qualified GHCup.Brick.Widgets.Menus.AdvancedInstall as AdvancedInstall import qualified GHCup.Brick.Widgets.Menus.CompileGHC as CompileGHC import           GHCup.Brick.Widgets.Menu (MenuKeyBindings(..))+import qualified Brick.Widgets.List     as L import qualified Brick-import qualified Graphics.Vty as Vty  import Control.Monad.Reader ( ReaderT(runReaderT) ) import Data.Functor ( ($>) )@@ -41,6 +40,8 @@  import qualified Data.Text                     as T import qualified GHCup.Brick.Widgets.Menus.CompileHLS as CompileHLS+import Data.Maybe (isNothing)+import qualified Data.Map.Strict as M   @@ -53,7 +54,7 @@   case eAppData of     Right ad -> do       let initial_list = Actions.constructList ad Common.defaultAppSettings Nothing-          current_element = Navigation.sectionListSelectedElement initial_list+          current_element = L.listSelectedElement initial_list           exit_key =             let KeyBindings {..} = keyBindings s             in MenuKeyBindings { mKbUp = bUp, mKbDown = bDown, mKbQuit = bQuit}@@ -61,25 +62,32 @@         Nothing -> do           flip runReaderT s $ logError "Error building app state: empty ResultList"           exitWith $ ExitFailure 2-        Just (_, e) ->-          let initapp =-                BrickApp.app-                  (Attributes.defaultAttributes $ noColor $ settings s)-                  (Attributes.dimAttributes $ noColor $ settings s)-              installedGHCs = fmap lVer $-                filter (\(ListResult {..}) -> lInstalled && lTool == GHC && lCross == Nothing) (Common._lr ad)-              initstate =-                AppState.BrickState ad-                      Common.defaultAppSettings-                      initial_list-                      (ContextMenu.create e exit_key)-                      (AdvanceInstall.create exit_key)-                      (CompileGHC.create exit_key installedGHCs)-                      (CompileHLS.create exit_key installedGHCs)-                      (keyBindings s)-                      Common.Navigation-          in Brick.defaultMain initapp initstate-          $> ()+        Just (_, (t, (td, vlr))) ->+          case L.listSelectedElement vlr of+            Nothing -> do+              flip runReaderT s $ logError "Error building app state: empty ResultList"+              exitWith $ ExitFailure 2+            Just (_, lr) ->+              let initapp =+                    BrickApp.app+                      (Attributes.defaultAttributes $ noColor $ settings s)+                      (Attributes.dimAttributes $ noColor $ settings s)+                  installedGHCs = maybe [] (fmap lVer) $ do+                    (_, lr') <- M.lookup (Tool "ghc") $ Common._lr ad+                    pure $ filter (\(ListResult {..}) -> lInstalled && isNothing lCross) lr'+                  initstate =+                    AppState.BrickState ad+                          Common.defaultAppSettings+                          initial_list+                          (ContextMenu.create (t, (td, lr)) exit_key)+                          (AdvancedInstall.create exit_key)+                          (CompileGHC.create exit_key installedGHCs)+                          (CompileHLS.create exit_key installedGHCs)+                          (keyBindings s)+                          Common.Navigation+                          False+              in Brick.defaultMain initapp initstate+              $> ()     Left e -> do       flip runReaderT s $ logError $ "Error building app state: " <> T.pack (show e)       exitWith $ ExitFailure 2
− lib/GHCup.hs
@@ -1,680 +0,0 @@-{-# LANGUAGE CPP                   #-}-{-# LANGUAGE BangPatterns          #-}-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE FlexibleInstances     #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE QuasiQuotes           #-}--{-|-Module      : GHCup-Description : GHCup installation functions-Copyright   : (c) Julian Ospald, 2020-License     : LGPL-3.0-Maintainer  : hasufell@hasufell.de-Stability   : experimental-Portability : portable--This module contains the main functions that correspond-to the command line interface, like installation, listing versions-and so on.--These are the entry points.--}-module GHCup (-  module GHCup,-  module GHCup.Cabal,-  module GHCup.GHC,-  module GHCup.HLS,-  module GHCup.Stack,-  module GHCup.List-) where---import           GHCup.Cabal-import           GHCup.GHC             hiding ( GHCVer(..) )-import           GHCup.HLS             hiding ( HLSVer(..) )-import           GHCup.Stack-import           GHCup.List-import           GHCup.Download-import           GHCup.Errors-import           GHCup.Platform-import           GHCup.Types-import           GHCup.Types.JSON               ( )-import           GHCup.Types.Optics-import           GHCup.Utils-import           GHCup.Prelude-import           GHCup.Prelude.File-import           GHCup.Prelude.Logger-import           GHCup.Prelude.String.QQ-import           GHCup.Version--import           Conduit (sourceToList)-import           Control.Applicative-import           Control.Exception.Safe-import           Control.Monad-#if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )-#endif-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-                                         hiding ( throwM )-import           Data.ByteString                ( ByteString )-import           Data.Either-import           Data.List-import           Data.Maybe-import           Data.Versions                hiding ( patch )-import           GHC.IO.Exception-import           Data.Variant.Excepts-import           Optics-import           Prelude                 hiding ( abs-                                                , writeFile-                                                )-import           System.Environment-import           System.FilePath-import           System.IO.Error-import           System.IO.Temp-import           Text.Regex.Posix--import qualified Data.Text                     as T-----    ----------------------    --[ Tool fetching ]---    ------------------------fetchToolBindist :: ( MonadFail m-                    , MonadMask m-                    , MonadCatch m-                    , MonadReader env m-                    , HasDirs env-                    , HasSettings env-                    , HasPlatformReq env-                    , HasGHCupInfo env-                    , HasLog env-                    , MonadResource m-                    , MonadIO m-                    , MonadUnliftIO m-                    )-                 => GHCTargetVersion-                 -> Tool-                 -> Maybe FilePath-                 -> Excepts-                      '[ DigestError-                       , ContentLengthError-                       , GPGError-                       , DownloadFailed-                       , NoDownload-                       , URIParseError-                       ]-                      m-                      FilePath-fetchToolBindist v t mfp = do-  dlinfo <- liftE $ getDownloadInfo' t v-  liftE $ downloadCached' dlinfo Nothing mfp----    -------------    --[ Nuke ]---    -----------------rmTool :: ( MonadReader env m-          , HasDirs env-          , HasLog env-          , MonadFail m-          , MonadMask m-          , MonadUnliftIO m)-          => ListResult-          -> Excepts '[NotInstalled, UninstallFailed] m ()-rmTool ListResult {lVer, lTool, lCross} = do-  let printRmTool = logInfo $ "removing " <> T.pack (show lTool) <> " version " <> prettyVer lVer-  case lTool of-    GHC -> do-      let ghcTargetVersion = GHCTargetVersion lCross lVer-      logInfo $ "removing " <> T.pack (show lTool) <> " version " <> tVerToText ghcTargetVersion-      rmGHCVer ghcTargetVersion-    HLS -> do-      printRmTool-      rmHLSVer lVer-    Cabal -> do-      printRmTool-      liftE $ rmCabalVer lVer-    Stack -> do-      printRmTool-      liftE $ rmStackVer lVer-    GHCup -> do-      printRmTool-      lift rmGhcup---rmGhcupDirs :: ( MonadReader env m-               , HasDirs env-               , MonadIO m-               , MonadUnliftIO m-               , HasLog env-               , MonadCatch m-               , MonadMask m )-            => m [FilePath]-rmGhcupDirs = do-  Dirs-    { baseDir-    , binDir-    , logsDir-    , cacheDir-    , recycleDir-    , dbDir-    , tmpDir-    } <- getDirs--  let envFilePath = fromGHCupPath baseDir </> "env"--  confFilePath <- getConfigFilePath--  handleRm $ rmEnvFile  envFilePath-  handleRm $ rmConfFile confFilePath--  -- for xdg dirs, the order matters here-  handleRm $ rmPathForcibly logsDir-  handleRm $ rmPathForcibly tmpDir-  handleRm $ rmPathForcibly cacheDir--  handleRm $ rmBinDir binDir-  handleRm $ rmPathForcibly recycleDir-  handleRm $ rmPathForcibly dbDir-  when isWindows $ do-    logInfo $ "removing " <> T.pack (fromGHCupPath baseDir </> "msys64")-    handleRm $ rmPathForcibly (baseDir `appendGHCupPath` "msys64")--  handleRm $ removeEmptyDirsRecursive (fromGHCupPath baseDir)--  -- report files in baseDir that are left-over after-  -- the standard location deletions above-  hideErrorDef [doesNotExistErrorType] [] $ reportRemainingFiles (fromGHCupPath baseDir)--  where-    handleRm :: (MonadReader env m, MonadCatch m, HasLog env, MonadIO m)  => m () -> m ()-    handleRm = handleIO (\e -> logDebug $ "Part of the cleanup action failed with error: " <> T.pack (displayException e) <> "\n"-                                <> "continuing regardless...")--    rmEnvFile :: (HasLog env, MonadReader env m, HasDirs env, MonadMask m, MonadIO m, MonadCatch m) => FilePath -> m ()-    rmEnvFile enFilePath = do-      logInfo "Removing Ghcup Environment File"-      hideErrorDef [permissionErrorType] () $ rmFileForce enFilePath--    rmConfFile :: (HasLog env, MonadReader env m, HasDirs env, MonadMask m, MonadIO m, MonadCatch m) => FilePath -> m ()-    rmConfFile confFilePath = do-      logInfo "removing Ghcup Config File"-      hideErrorDef [permissionErrorType] () $ rmFileForce confFilePath--    rmBinDir :: (MonadReader env m, HasDirs env, MonadMask m, MonadIO m, MonadCatch m) => FilePath -> m ()-    rmBinDir binDir-      | isWindows = removeDirIfEmptyOrIsSymlink binDir-      | otherwise = do-          isXDGStyle <- liftIO useXDG-          when (not isXDGStyle) $-            removeDirIfEmptyOrIsSymlink binDir--    reportRemainingFiles :: (MonadMask m, MonadIO m, MonadUnliftIO m) => FilePath -> m [FilePath]-    reportRemainingFiles dir = do-      remainingFiles <- runResourceT $ sourceToList $ getDirectoryContentsRecursiveUnsafe dir-      let normalizedFilePaths = fmap normalise remainingFiles-      let sortedByDepthRemainingFiles = sortBy (flip compareFn) normalizedFilePaths-      let remainingFilesAbsolute = fmap (dir </>) sortedByDepthRemainingFiles--      pure remainingFilesAbsolute--      where-        calcDepth :: FilePath -> Int-        calcDepth = length . filter isPathSeparator--        compareFn :: FilePath -> FilePath -> Ordering-        compareFn fp1 fp2 = compare (calcDepth fp1) (calcDepth fp2)-----    -------------------    --[ Debug info ]---    ---------------------getDebugInfo :: ( Alternative m-                , MonadFail m-                , MonadReader env m-                , HasDirs env-                , HasLog env-                , MonadCatch m-                , MonadIO m-                )-             => Excepts-                  '[NoCompatiblePlatform , NoCompatibleArch , DistroNotFound]-                  m-                  DebugInfo-getDebugInfo = do-  diDirs <- lift getDirs-  let diChannels = fmap (\c -> (c, channelURL c)) [minBound..maxBound]-  let diShimGenURL = shimGenURL-  diArch         <- lE getArchitecture-  diPlatform     <- liftE getPlatform-  pure $ DebugInfo { .. }-----    --------------------------    --[ GHCup upgrade etc ]---    ----------------------------- | Upgrade ghcup and place it in @~\/.ghcup\/bin\/ghcup@,--- if no path is provided.-upgradeGHCup :: ( MonadMask m-                , MonadReader env m-                , HasDirs env-                , HasPlatformReq env-                , HasGHCupInfo env-                , HasSettings env-                , MonadCatch m-                , HasLog env-                , MonadThrow m-                , MonadFail m-                , MonadResource m-                , MonadIO m-                , MonadUnliftIO m-                )-             => Maybe FilePath    -- ^ full file destination to write ghcup into-             -> Bool              -- ^ whether to force update regardless-                                  --   of currently installed version-             -> Bool              -- ^ whether to throw an error if ghcup is shadowed-             -> Excepts-                  '[ CopyError-                   , DigestError-                   , ContentLengthError-                   , GPGError-                   , GPGError-                   , DownloadFailed-                   , NoDownload-                   , NoUpdate-                   , ToolShadowed-                   , URIParseError-                   ]-                  m-                  Version-upgradeGHCup mtarget force' fatal = do-  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-  let latestVer = _tvVersion $ fst (fromJust (getLatest dls GHCup))-  upgradeGHCup' mtarget force' fatal latestVer----- | Upgrade ghcup and place it in @~\/.ghcup\/bin\/ghcup@,--- if no path is provided.-upgradeGHCup' :: ( MonadMask m-                 , MonadReader env m-                 , HasDirs env-                 , HasPlatformReq env-                 , HasGHCupInfo env-                 , HasSettings env-                 , MonadCatch m-                 , HasLog env-                 , MonadThrow m-                 , MonadFail m-                 , MonadResource m-                 , MonadIO m-                 , MonadUnliftIO m-                 )-              => Maybe FilePath    -- ^ full file destination to write ghcup into-              -> Bool              -- ^ whether to force update regardless-                                   --   of currently installed version-              -> Bool              -- ^ whether to throw an error if ghcup is shadowed-              -> Version-              -> Excepts-                   '[ CopyError-                    , DigestError-                    , ContentLengthError-                    , GPGError-                    , GPGError-                    , DownloadFailed-                    , NoDownload-                    , NoUpdate-                    , ToolShadowed-                    , URIParseError-                    ]-                   m-                   Version-upgradeGHCup' mtarget force' fatal latestVer = do-  Dirs {..} <- lift getDirs-  lift $ logInfo "Upgrading GHCup..."-  (Just ghcupPVPVer) <- pure $ pvpToVersion ghcUpVer ""-  when (not force' && (latestVer <= ghcupPVPVer)) $ throwE NoUpdate-  dli   <- liftE $ getDownloadInfo GHCup latestVer-  tmp   <- fromGHCupPath <$> lift withGHCupTmpDir-  let fn = "ghcup" <> exeExt-  dlu <- lE $ parseURI' (_dlUri dli)-  p <- liftE $ download dlu Nothing (Just (_dlHash dli)) (_dlCSize dli) tmp (Just fn) False-  let destDir = takeDirectory destFile-      destFile = fromMaybe (binDir </> fn) mtarget-  lift $ logDebug $ "mkdir -p " <> T.pack destDir-  liftIO $ createDirRecursive' destDir-  lift $ logDebug $ "rm -f " <> T.pack destFile-  lift $ hideError NoSuchThing $ recycleFile destFile-  lift $ logDebug $ "cp " <> T.pack p <> " " <> T.pack destFile-  copyFileE p destFile False-  lift $ chmod_755 destFile--  liftIO (isInPath destFile) >>= \b -> unless b $-    lift $ logWarn $ T.pack (takeFileName destFile) <> " is not in PATH! You have to add it in order to use ghcup."-  liftIO (isShadowed destFile) >>= \case-    Nothing -> pure ()-    Just pa-      | fatal -> throwE (ToolShadowed GHCup pa destFile latestVer)-      | otherwise ->-        lift $ logWarn $ T.pack $ prettyHFError (ToolShadowed GHCup pa destFile latestVer)--  pure latestVer----- assuming the current scheme of having just 1 ghcup bin, no version info is required.-rmGhcup :: ( MonadReader env m-           , HasDirs env-           , MonadIO m-           , MonadCatch m-           , HasLog env-           , MonadMask m-           , MonadUnliftIO m-           )-        => m ()-rmGhcup = do-  Dirs { .. } <- getDirs-  let ghcupFilename = "ghcup" <> exeExt-  let ghcupFilepath = binDir </> ghcupFilename--  currentRunningExecPath <- liftIO getExecutablePath--  -- if paths do no exist, warn user, and continue to compare them, as is,-  -- which should eventually fail and result in a non-standard install warning--  p1 <- handleIO' doesNotExistErrorType-                  (handlePathNotPresent currentRunningExecPath)-                  (liftIO $ canonicalizePath currentRunningExecPath)--  p2 <- handleIO' doesNotExistErrorType-                  (handlePathNotPresent ghcupFilepath)-                  (liftIO $ canonicalizePath ghcupFilepath)--  let areEqualPaths = equalFilePath p1 p2--  unless areEqualPaths $ logWarn $ nonStandardInstallLocationMsg currentRunningExecPath--  if isWindows-  then do-    -- since it doesn't seem possible to delete a running exe on windows-    -- we move it to system temp dir, to be deleted at next reboot-    tmp <- liftIO $ getCanonicalTemporaryDirectory >>= \t -> createTempDirectory t "ghcup"-    logDebug $ "mv " <> T.pack ghcupFilepath <> " " <> T.pack (tmp </> "ghcup")-    hideError UnsupportedOperation $-              liftIO $ hideError NoSuchThing $-              moveFile ghcupFilepath (tmp </> "ghcup")-  else-    -- delete it.-    hideError doesNotExistErrorType $ rmFile ghcupFilepath--  where-    handlePathNotPresent fp _err = do-      logDebug $ "Error: The path does not exist, " <> T.pack fp-      pure fp--    nonStandardInstallLocationMsg path = T.pack $-      "current ghcup is invoked from a non-standard location: \n"-      <> path <>-      "\n you may have to uninstall it manually."----    ----------------    --[ Whereis ]---    --------------------- | Reports the binary location of a given tool:------   * for GHC, this reports: @~\/.ghcup\/ghc\/\<ver\>\/bin\/ghc@---   * for cabal, this reports @~\/.ghcup\/bin\/cabal-\<ver\>@---   * for hls, this reports @~\/.ghcup\/bin\/haskell-language-server-wrapper-\<ver\>@---   * for stack, this reports @~\/.ghcup\/bin\/stack-\<ver\>@---   * for ghcup, this reports the location of the currently running executable-whereIsTool :: ( MonadReader env m-               , HasDirs env-               , HasLog env-               , MonadThrow m-               , MonadFail m-               , MonadIO m-               , MonadCatch m-               , MonadMask m-               , MonadUnliftIO m-               )-            => Tool-            -> GHCTargetVersion-            -> Excepts '[NotInstalled] m FilePath-whereIsTool tool ver@GHCTargetVersion {..} = do-  dirs <- lift getDirs--  case tool of-    GHC -> do-      whenM (lift $ fmap not $ ghcInstalled ver)-        $ throwE (NotInstalled GHC ver)-      bdir <- fromGHCupPath <$> lift (ghcupGHCDir ver)-      pure (bdir </> "bin" </> ghcBinaryName ver)-    Cabal -> do-      whenM (lift $ fmap not $ cabalInstalled _tvVersion)-        $ throwE (NotInstalled Cabal (GHCTargetVersion Nothing _tvVersion))-      pure (binDir dirs </> "cabal-" <> T.unpack (prettyVer _tvVersion) <> exeExt)-    HLS -> do-      whenM (lift $ fmap not $ hlsInstalled _tvVersion)-        $ throwE (NotInstalled HLS (GHCTargetVersion Nothing _tvVersion))-      ifM (lift $ isLegacyHLS _tvVersion)-        (pure (binDir dirs </> "haskell-language-server-wrapper-" <> T.unpack (prettyVer _tvVersion) <> exeExt))-        $ do-          bdir <- fromGHCupPath <$> lift (ghcupHLSDir _tvVersion)-          pure (bdir </> "bin" </> "haskell-language-server-wrapper" <> exeExt)--    Stack -> do-      whenM (lift $ fmap not $ stackInstalled _tvVersion)-        $ throwE (NotInstalled Stack (GHCTargetVersion Nothing _tvVersion))-      pure (binDir dirs </> "stack-" <> T.unpack (prettyVer _tvVersion) <> exeExt)-    GHCup -> do-      currentRunningExecPath <- liftIO getExecutablePath-      liftIO $ canonicalizePath currentRunningExecPath----- | Doesn't work for cross GHC.-checkIfToolInstalled :: ( MonadIO m-                        , MonadReader env m-                        , HasDirs env-                        , MonadCatch m) =>-                        Tool ->-                        Version ->-                        m Bool-checkIfToolInstalled tool ver = checkIfToolInstalled' tool (mkTVer ver)---checkIfToolInstalled' :: ( MonadIO m-                         , MonadReader env m-                         , HasDirs env-                         , MonadCatch m) =>-                        Tool ->-                        GHCTargetVersion ->-                        m Bool-checkIfToolInstalled' tool ver =-  case tool of-    Cabal -> cabalInstalled (_tvVersion ver)-    HLS   -> hlsInstalled (_tvVersion ver)-    Stack -> stackInstalled (_tvVersion ver)-    GHC   -> ghcInstalled ver-    _     -> pure False-----    ---------------------------    --[ Garbage collection ]---    -----------------------------rmOldGHC :: ( MonadReader env m-            , HasGHCupInfo env-            , HasDirs env-            , HasLog env-            , MonadIO m-            , MonadFail m-            , MonadMask m-            , MonadUnliftIO m-            )-         => Excepts '[NotInstalled, UninstallFailed] m ()-rmOldGHC = do-  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-  let oldGHCs = toListOf (ix GHC % getTagged Old % to fst) dls-  ghcs <- lift $ fmap rights getInstalledGHCs-  forM_ ghcs $ \ghc -> when (ghc `elem` oldGHCs) $ rmGHCVer ghc---rmUnsetTools :: ( MonadReader env m-                , HasGHCupInfo env-                , HasPlatformReq env-                , HasDirs env-                , HasLog env-                , MonadIO m-                , MonadFail m-                , MonadMask m-                , MonadUnliftIO m-                )-             => Excepts '[NotInstalled, UninstallFailed] m ()-rmUnsetTools = do-  vers <- lift $ listVersions Nothing [ListInstalled True, ListSet False] False True (Nothing, Nothing)-  forM_ vers $ \ListResult{..} -> case lTool of-    GHC   -> liftE $ rmGHCVer (GHCTargetVersion lCross lVer)-    HLS   -> liftE $ rmHLSVer lVer-    Cabal -> liftE $ rmCabalVer lVer-    Stack -> liftE $ rmStackVer lVer-    GHCup -> pure ()---rmProfilingLibs :: ( MonadReader env m-                   , HasDirs env-                   , HasLog env-                   , MonadIO m-                   , MonadFail m-                   , MonadMask m-                   , MonadUnliftIO m-                   )-                => m ()-rmProfilingLibs = do-  ghcs <- fmap rights getInstalledGHCs--  let regexes :: [ByteString]-      regexes = [[s|.*_p\.a$|], [s|.*\.p_hi$|]]--  forM_ regexes $ \regex ->-    forM_ ghcs $ \ghc -> do-      d <- ghcupGHCDir ghc-      -- TODO: audit findFilesDeep-      matches <- liftIO $ handleIO (\_ -> pure []) $ findFilesDeep-        d-        (makeRegexOpts compExtended-                       execBlank-                       regex-        )-      forM_ matches $ \m -> do-        let p = fromGHCupPath d </> m-        logDebug $ "rm " <> T.pack p-        rmFile p----rmShareDir :: ( MonadReader env m-              , HasDirs env-              , HasLog env-              , MonadIO m-              , MonadFail m-              , MonadMask m-              , MonadUnliftIO m-              )-           => m ()-rmShareDir = do-  ghcs <- fmap rights getInstalledGHCs-  forM_ ghcs $ \ghc -> do-    d <- ghcupGHCDir ghc-    let p = d `appendGHCupPath` "share"-    logDebug $ "rm -rf " <> T.pack (fromGHCupPath p)-    rmPathForcibly p---rmHLSNoGHC :: ( MonadReader env m-              , HasDirs env-              , HasLog env-              , MonadIO m-              , MonadMask m-              , MonadFail m-              , MonadUnliftIO m-              )-           => Excepts '[NotInstalled, UninstallFailed] m ()-rmHLSNoGHC = do-  Dirs {..} <- getDirs-  ghcs <- fmap rights getInstalledGHCs-  hlses <- fmap rights getInstalledHLSs-  forM_ hlses $ \hls -> do-    hlsGHCs <- fmap mkTVer <$> hlsGHCVersions' hls-    let candidates = filter (`notElem` ghcs) hlsGHCs-    if (length hlsGHCs - length candidates) <= 0-    then rmHLSVer hls-    else-      forM_ candidates $ \ghc -> do-        bins1 <- fmap (binDir </>) <$> hlsServerBinaries hls (Just $ _tvVersion ghc)-        bins2 <- ifM (isLegacyHLS hls) (pure []) $ do-          shs <- hlsInternalServerScripts hls (Just $ _tvVersion ghc)-          bins <- hlsInternalServerBinaries hls (Just $ _tvVersion ghc)-          libs <- hlsInternalServerLibs hls (_tvVersion ghc)-          pure (shs ++ bins ++ libs)-        forM_ (bins1 ++ bins2) $ \f -> do-          logDebug $ "rm " <> T.pack f-          rmFile f-    pure ()---rmCache :: ( MonadReader env m-           , HasDirs env-           , HasLog env-           , MonadIO m-           , MonadMask m-           )-        => m ()-rmCache = do-  Dirs {..} <- getDirs-  contents <- liftIO $ listDirectory (fromGHCupPath cacheDir)-  forM_ contents $ \f -> do-    let p = fromGHCupPath cacheDir </> f-    logDebug $ "rm " <> T.pack p-    rmFile p---rmTmp :: ( MonadReader env m-         , HasDirs env-         , HasLog env-         , MonadIO m-         , MonadMask m-         )-      => m ()-rmTmp = do-  ghcup_dirs <- liftIO getGHCupTmpDirs-  forM_ ghcup_dirs $ \f -> do-    logDebug $ "rm -rf " <> T.pack (fromGHCupPath f)-    rmPathForcibly f--
+ lib/GHCup/Builder.hs view
@@ -0,0 +1,104 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}++module GHCup.Builder where++import GHCup.Errors+import GHCup.Prelude+import GHCup.Query.GHCupDirs+import GHCup.Types+import GHCup.Types.Optics++import Control.Exception.Safe+    ( Exception (displayException), handleIO, onException )+import Control.Monad+import Control.Monad.IO.Unlift ( MonadUnliftIO (withRunInIO) )+import Control.Monad.Reader    ( MonadIO (..), MonadReader, MonadTrans (lift) )+import Data.Foldable           ( foldlM )+import Data.List               ( sort )+import Data.Variant.Excepts    ( Excepts, onE_, throwE )+import System.FilePath         ( pathSeparators )+import System.IO.Error         ( doesNotExistErrorType )+import Text.Regex.Posix+    ( RegexMaker (makeRegexOpts), compIgnoreCase, execBlank )++import qualified Data.Text              as T+import           GHCup.System.Directory+++-- | Execute a build action while potentially cleaning up:+--+--   1. the build directory, depending on the KeepDirs setting+runBuildAction :: ( MonadReader env m+                  , HasDirs env+                  , HasSettings env+                  , MonadIOish m+                  , HasLog env+                  )+               => GHCupPath        -- ^ build directory (cleaned up depending on Settings)+               -> Excepts e m a+               -> Excepts e m a+runBuildAction bdir action = do+  Settings {..} <- lift getSettings+  let exAction = do+        when (keepDirs == Never)+          $ rmBDir bdir+  v <-+    flip onException (lift exAction)+    $ onE_ exAction action+  when (keepDirs == Never || keepDirs == Errors) $ lift $ rmBDir bdir+  pure v++-- | Clean up the given directory if the action fails,+-- depending on the Settings.+cleanUpOnError :: forall e m a env .+                  ( MonadReader env m+                  , HasDirs env+                  , HasSettings env+                  , MonadIOish m+                  , HasLog env+                  )+               => GHCupPath        -- ^ build directory (cleaned up depending on Settings)+               -> Excepts e m a+               -> Excepts e m a+cleanUpOnError bdir action = do+  Settings {..} <- lift getSettings+  let exAction = when (keepDirs == Never) $ rmBDir bdir+  flip onException (lift exAction) $ onE_ exAction action+++-- | Remove a build directory, ignoring if it doesn't exist and gracefully+-- printing other errors without crashing.+rmBDir :: (MonadReader env m, HasLog env, MonadIOish m) => GHCupPath -> m ()+rmBDir dir = withRunInIO (\run -> run $+           liftIO $ handleIO (\e -> run $ logWarn $+               "Couldn't remove build dir " <> T.pack (fromGHCupPath dir) <> ", error was: " <> T.pack (displayException e))+           $ hideError doesNotExistErrorType+           $ rmPathForcibly dir)+++++intoSubdir :: (MonadReader env m, HasLog env, MonadIOish m)+           => GHCupPath       -- ^ unpacked tar dir+           -> TarDir         -- ^ how to descend+           -> Excepts '[TarDirDoesNotExist] m GHCupPath+intoSubdir bdir tardir = case tardir of+  RealDir pr -> do+    whenM (fmap not . liftIO . doesDirectoryExist $ fromGHCupPath (bdir `appendGHCupPath` pr))+          (throwE $ TarDirDoesNotExist tardir)+    pure (bdir `appendGHCupPath` pr)+  RegexDir r -> do+    let rs = split (`elem` pathSeparators) r+    foldlM+      (\y x ->+        (handleIO (\_ -> pure []) . liftIO . findFiles (fromGHCupPath y) . regex $ x) >>= (\case+          []      -> throwE $ TarDirDoesNotExist tardir+          (p : _) -> pure (y `appendGHCupPath` p)) . sort+      )+      bdir+      rs+    where regex = makeRegexOpts compIgnoreCase execBlank+
− lib/GHCup/Cabal.hs
@@ -1,287 +0,0 @@-{-# LANGUAGE CPP                   #-}-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE FlexibleInstances     #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedStrings     #-}--{-|-Module      : GHCup.Cabal-Description : GHCup installation functions for Cabal-Copyright   : (c) Julian Ospald, 2020-License     : LGPL-3.0-Maintainer  : hasufell@hasufell.de-Stability   : experimental-Portability : portable--}-module GHCup.Cabal where--import           GHCup.Download-import           GHCup.Errors-import           GHCup.Types-import           GHCup.Types.JSON               ( )-import           GHCup.Types.Optics-import           GHCup.Utils-import           GHCup.Prelude-import           GHCup.Prelude.File-import           GHCup.Prelude.Logger--import           Control.Applicative-import           Control.Exception.Safe-import           Control.Monad-#if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )-#endif-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-                                         hiding ( throwM )-import           Data.Either-import           Data.List-import           Data.Ord-import           Data.Maybe-import           Data.Versions                hiding ( patch )-import           Data.Variant.Excepts-import           Optics-import           Prelude                 hiding ( abs-                                                , writeFile-                                                )-import           Safe                    hiding ( at )-import           System.FilePath-import           System.IO.Error--import qualified Data.Text                     as T----    --------------------------    --[ Tool installation ]---    ------------------------------ | Like 'installCabalBin', except takes the 'DownloadInfo' as--- argument instead of looking it up from 'GHCupDownloads'.-installCabalBindist :: ( MonadMask m-                       , MonadCatch m-                       , MonadReader env m-                       , HasPlatformReq env-                       , HasDirs env-                       , HasSettings env-                       , HasLog env-                       , MonadResource m-                       , MonadIO m-                       , MonadUnliftIO m-                       , MonadFail m-                       )-                    => DownloadInfo-                    -> Version-                    -> InstallDir-                    -> Bool           -- ^ Force install-                    -> Excepts-                         '[ AlreadyInstalled-                          , CopyError-                          , DigestError-                          , ContentLengthError-                          , GPGError-                          , DownloadFailed-                          , NoDownload-                          , NotInstalled-                          , UnknownArchive-                          , TarDirDoesNotExist-                          , ArchiveResult-                          , FileAlreadyExistsError-                          , URIParseError-                          ]-                         m-                         ()-installCabalBindist dlinfo ver installDir forceInstall = do-  lift $ logDebug $ "Requested to install cabal version " <> prettyVer ver--  PlatformRequest {..} <- lift getPlatformReq-  Dirs {..} <- lift getDirs--  -- check if we already have a regular cabal already installed-  regularCabalInstalled <- lift $ cabalInstalled ver--  if-    | not forceInstall-    , regularCabalInstalled-    , GHCupInternal <- installDir -> do-        throwE $ AlreadyInstalled Cabal ver--    | forceInstall-    , regularCabalInstalled-    , GHCupInternal <- installDir -> do-        lift $ logInfo "Removing the currently installed version first!"-        liftE $ rmCabalVer ver--    | otherwise -> pure ()---  -- download (or use cached version)-  dl <- liftE $ downloadCached dlinfo Nothing--  -- unpack-  tmpUnpack <- lift withGHCupTmpDir-  liftE $ cleanUpOnError tmpUnpack (unpackToDir (fromGHCupPath tmpUnpack) dl)-  liftE $ catchWarn $ lEM @_ @'[ProcessError] $ darwinNotarization _rPlatform (fromGHCupPath tmpUnpack)--  -- the subdir of the archive where we do the work-  workdir <- fromGHCupPath <$> maybe (pure tmpUnpack) (liftE . intoSubdir tmpUnpack) (view dlSubdir dlinfo)--  case installDir of-    IsolateDir isoDir -> do             -- isolated install-      lift $ logInfo $ "isolated installing Cabal to " <> T.pack isoDir-      liftE $ installCabalUnpacked workdir (IsolateDirResolved isoDir) ver forceInstall--    GHCupInternal -> do                 -- regular install-      liftE $ installCabalUnpacked workdir (GHCupBinDir binDir) ver forceInstall----- | Install an unpacked cabal distribution.Symbol-installCabalUnpacked :: (MonadCatch m, HasLog env, MonadIO m, MonadReader env m)-              => FilePath      -- ^ Path to the unpacked cabal bindist (where the executable resides)-              -> InstallDirResolved      -- ^ Path to install to-              -> Version-              -> Bool          -- ^ Force Install-              -> Excepts '[CopyError, FileAlreadyExistsError] m ()-installCabalUnpacked path inst ver forceInstall = do-  lift $ logInfo "Installing cabal"-  let cabalFile = "cabal"-  liftIO $ createDirRecursive' (fromInstallDir inst)-  let destFileName = cabalFile-        <> (case inst of-              IsolateDirResolved _ -> ""-              _ -> ("-" <>) . T.unpack . prettyVer $ ver-           )-        <> exeExt-  let destPath = fromInstallDir inst </> destFileName--  copyFileE-    (path </> cabalFile <> exeExt)-    destPath-    (not forceInstall)-  lift $ chmod_755 destPath---- | Installs cabal into @~\/.ghcup\/bin/cabal-\<ver\>@ and--- creates a default @cabal -> cabal-x.y.z.q@ symlink for--- the latest installed version.-installCabalBin :: ( MonadMask m-                   , MonadCatch m-                   , MonadReader env m-                   , HasPlatformReq env-                   , HasGHCupInfo env-                   , HasDirs env-                   , HasSettings env-                   , HasLog env-                   , MonadResource m-                   , MonadIO m-                   , MonadUnliftIO m-                   , MonadFail m-                   )-                => Version-                -> InstallDir-                -> Bool           -- force install-                -> Excepts-                     '[ AlreadyInstalled-                      , CopyError-                      , DigestError-                      , ContentLengthError-                      , GPGError-                      , DownloadFailed-                      , NoDownload-                      , NotInstalled-                      , UnknownArchive-                      , TarDirDoesNotExist-                      , ArchiveResult-                      , FileAlreadyExistsError-                      , URIParseError-                      ]-                     m-                     ()-installCabalBin ver installDir forceInstall = do-  dlinfo <- liftE $ getDownloadInfo Cabal ver-  installCabalBindist dlinfo ver installDir forceInstall---    ------------------    --[ Set cabal ]---    ---------------------- | Set the @~\/.ghcup\/bin\/cabal@ symlink.-setCabal :: ( MonadMask m-            , MonadReader env m-            , HasDirs env-            , HasLog env-            , MonadFail m-            , MonadIO m-            , MonadUnliftIO m)-         => Version-         -> Excepts '[NotInstalled] m ()-setCabal ver = do-  let targetFile = "cabal-" <> T.unpack (prettyVer ver) <> exeExt--  -- symlink destination-  Dirs {..} <- lift getDirs--  whenM (liftIO $ not <$> doesFileExist (binDir </> targetFile))-    $ throwE-    $ NotInstalled Cabal (GHCTargetVersion Nothing ver)--  let cabalbin = binDir </> "cabal" <> exeExt--  -- create link-  let destL = targetFile-  lift $ createLink destL cabalbin--  liftIO (isShadowed cabalbin) >>= \case-    Nothing -> pure ()-    Just pa -> lift $ logWarn $ T.pack $ prettyHFError (ToolShadowed Cabal pa cabalbin ver)--  pure ()--unsetCabal :: ( MonadMask m-              , MonadReader env m-              , HasDirs env-              , MonadIO m)-           => m ()-unsetCabal = do-  Dirs {..} <- getDirs-  let cabalbin = binDir </> "cabal" <> exeExt-  hideError doesNotExistErrorType $ rmLink cabalbin---    -----------------    --[ Rm cabal ]---    --------------------- | Delete a cabal version. Will try to fix the @cabal@ symlink--- after removal (e.g. setting it to an older version).-rmCabalVer :: ( MonadMask m-              , MonadReader env m-              , HasDirs env-              , MonadThrow m-              , HasLog env-              , MonadIO m-              , MonadFail m-              , MonadCatch m-              , MonadUnliftIO m-              )-           => Version-           -> Excepts '[NotInstalled] m ()-rmCabalVer ver = do-  whenM (lift $ fmap not $ cabalInstalled ver) $ throwE (NotInstalled Cabal (GHCTargetVersion Nothing ver))--  cSet      <- lift cabalSet--  Dirs {..} <- lift getDirs--  let cabalFile = "cabal-" <> T.unpack (prettyVer ver) <> exeExt-  lift $ hideError doesNotExistErrorType $ recycleFile (binDir </> cabalFile)--  when (Just ver == cSet) $ do-    cVers <- lift $ fmap rights getInstalledCabals-    case headMay . sortBy (comparing Down) $ cVers of-      Just latestver -> setCabal latestver-      Nothing        -> lift $ rmLink (binDir </> "cabal" <> exeExt)
lib/GHCup/CabalConfig.hs view
@@ -1,28 +1,29 @@-{-# LANGUAGE CPP                  #-}-{-# LANGUAGE OverloadedStrings    #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE UndecidableInstances #-}  module GHCup.CabalConfig (getStoreDir) where -import Data.ByteString          (ByteString)-import Data.List.NonEmpty       (NonEmpty)-import Data.Map                 (Map)-import System.Directory         (getAppUserDataDirectory, doesDirectoryExist, getXdgDirectory, XdgDirectory(XdgConfig))-import System.Environment       (lookupEnv)-import System.FilePath          ((</>))+import GHCup.System.Directory -import qualified Data.ByteString               as BS-import qualified Data.Map.Strict               as M-import qualified Distribution.CabalSpecVersion as C-import qualified Distribution.FieldGrammar     as C-import qualified Distribution.FieldGrammar.Parsec     as C-import qualified Distribution.Fields           as C-import qualified Distribution.Fields.LexerMonad as C-import qualified Distribution.Parsec           as C-import qualified Distribution.Utils.Generic    as C-import qualified Text.Parsec                    as P+import Data.ByteString    ( ByteString )+import Data.List.NonEmpty ( NonEmpty )+import Data.Map           ( Map )+import System.Environment ( lookupEnv )+import System.FilePath    ( (</>) ) -import Data.Foldable              (for_)+import qualified Data.ByteString                  as BS+import qualified Data.Map.Strict                  as M+import qualified Distribution.CabalSpecVersion    as C+import qualified Distribution.FieldGrammar        as C+import qualified Distribution.FieldGrammar.Parsec as C+import qualified Distribution.Fields              as C+import qualified Distribution.Fields.LexerMonad   as C+import qualified Distribution.Parsec              as C+import qualified Distribution.Utils.Generic       as C+import qualified Text.Parsec                      as P++import Data.Foldable             ( for_ ) import Distribution.Parsec.Error  @@ -55,8 +56,8 @@     appDir <- getAppUserDataDirectory "cabal"     isXdg <- not <$> doesDirectoryExist appDir     if | Just dir <- cabalDirVar -> pure dir-       | isXdg -> getXdgDirectory XdgConfig "cabal"-       | otherwise -> pure appDir+       | isXdg                   -> getXdgDirectory XdgConfig "cabal"+       | otherwise               -> pure appDir   -------------------------------------------------------------------------------
+ lib/GHCup/Command/Compile/GHC.hs view
@@ -0,0 +1,834 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}++{-|+Module      : GHCup.Command.Compile.GHC+Description : GHCup compile GHC+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Command.Compile.GHC where+++import GHCup.Builder+import GHCup.Command.Install+import GHCup.Command.Install.LowLevel+import GHCup.Command.Rm+import GHCup.Command.Set+import GHCup.Download+import GHCup.Errors+import GHCup.Prelude+import GHCup.Prelude.MegaParsec+import GHCup.Prelude.Process+import GHCup.Prelude.String.QQ+import GHCup.Prelude.Version.QQ+import GHCup.Query.DB+import GHCup.Query.GHCupDirs+import GHCup.System.Cmd+import GHCup.System.Directory+import GHCup.Types+import GHCup.Types.Optics+import GHCup.Unpack++import Control.Applicative+import Control.Concurrent     ( threadDelay )+import Control.Exception.Safe+import Control.Monad+#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Monad.Reader+import Control.Monad.Trans.Resource   hiding ( throwM )+import Data.ByteString                ( ByteString )+import Data.Either+import Data.List+import Data.Maybe+import Data.String                    ( fromString )+import Data.Text                      ( Text )+import Data.Time.Clock+import Data.Time.Format.ISO8601+import Data.Variant.Excepts+import Data.Versions                  hiding ( patch )+import GHC.IO.Exception+import Language.Haskell.TH+import Language.Haskell.TH.Syntax     ( Quasi (qAddDependentFile) )+import Optics+import Prelude                        hiding ( abs, writeFile )+import System.Environment+import System.FilePath+import System.FilePattern ((?==))+import System.IO.Error+import Text.PrettyPrint.HughesPJClass ( prettyShow )+import Text.Regex.Posix+import URI.ByteString++import qualified Crypto.Hash.SHA256     as SHA256+import qualified Data.ByteString        as B+import qualified Data.ByteString.Base16 as B16+import qualified Data.ByteString.Lazy   as BL+import qualified Data.Map.Strict        as Map+import qualified Data.Text              as T+import qualified Data.Text.Encoding     as E+import qualified Data.Text.IO           as T+import qualified System.FilePath.Posix  as Posix+import qualified Text.Megaparsec        as MP+++data GHCVer+  = SourceDist Version+  | GitDist GitBranch+  | RemoteDist URI+  deriving (Eq, Show)+++++    -------------------------+    --[ Tool installation ]--+    -------------------------+++++mergeGHCFileTree :: ( MonadReader env m+                    , HasPlatformReq env+                    , HasDirs env+                    , HasSettings env+                    , MonadThrow m+                    , HasLog env+                    , MonadIO m+                    , MonadUnliftIO m+                    , MonadMask m+                    , MonadResource m+                    , MonadFail m+                    )+                 => GHCupPath           -- ^ Path to the root of the tree+                 -> InstallDirResolved  -- ^ Path to install to+                 -> TargetVersion    -- ^ The GHC version+                 -> Bool                -- ^ Force install+                 -> Excepts '[MergeFileTreeError] m ()+mergeGHCFileTree root inst tver forceInstall+  | isWindows = do+      liftE $ mergeFileTree root inst ghc tver (\source dest -> do+        mtime <- liftIO $ ifM (pathIsSymbolicLink source) (pure Nothing) (Just <$> getModificationTime source)+        when forceInstall $ hideError doesNotExistErrorType $ hideError InappropriateType $ recycleFile dest+        liftIO $ moveFilePortable source dest+        forM_ mtime $ liftIO . setModificationTime dest+        )+        False+  | otherwise = do+      liftE $ mergeFileTree root+        inst+        ghc+        tver+        (\f t -> liftIO $ do+            mtime <- ifM (pathIsSymbolicLink f) (pure Nothing) (Just <$> getModificationTime f)+            install f t (not forceInstall)+            forM_ mtime $ setModificationTime t)+        False+++++    ---------------+    --[ Compile ]--+    ---------------+++-- | Compile a GHC from source. This behaves wrt symlinks and installation+-- the same as 'installGHCBin'.+compileGHC :: ( MonadMask m+              , MonadReader env m+              , HasDirs env+              , HasPlatformReq env+              , HasGHCupInfo env+              , HasSettings env+              , MonadThrow m+              , MonadResource m+              , HasLog env+              , MonadIO m+              , MonadUnliftIO m+              , MonadFail m+              )+           => GHCVer+           -> Maybe Text               -- ^ cross target+           -> Maybe [VersionPattern]+           -> Either Version FilePath  -- ^ GHC version to bootstrap with+           -> Maybe (Either Version FilePath)  -- ^ GHC version to compile hadrian with+           -> Maybe Int                -- ^ jobs+           -> Maybe FilePath           -- ^ build config+           -> Maybe (Either FilePath [URI])  -- ^ patches+           -> [String]                   -- ^ additional args to ./configure+           -> Maybe String             -- ^ build flavour+           -> Maybe BuildSystem+           -> InstallDir+           -> Maybe [String]+           -> Excepts+                '[ AlreadyInstalled+                 , BuildFailed+                 , DigestError+                 , ContentLengthError+                 , GPGError+                 , DownloadFailed+                 , GHCupSetError+                 , NoDownload+                 , NotFoundInPATH+                 , PatchFailed+                 , UnknownArchive+                 , TarDirDoesNotExist+                 , NotInstalled+                 , DirNotEmpty+                 , ArchiveResult+                 , FileDoesNotExistError+                 , HadrianNotFound+                 , InvalidBuildConfig+                 , ProcessError+                 , CopyError+                 , BuildFailed+                 , UninstallFailed+                 , MergeFileTreeError+                 , URIParseError+                 , FileAlreadyExistsError+                 , ParseError+                 , NoInstallInfo+                 , MalformedInstallInfo+                 ]+                m+                TargetVersion+compileGHC targetGhc crossTarget vps bstrap hghc jobs mbuildConfig patches aargs buildFlavour buildSystem installDir installTargets+  = do+    pfreq@PlatformRequest { .. } <- lift getPlatformReq+    GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo++    (workdir, tmpUnpack, tver, ov) <- case targetGhc of+      -- unpack from version tarball+      SourceDist ver -> do+        let tver = mkTVer ver+        lift $ logDebug $ "Requested to compile: " <> prettyVer ver <> " with " <> either prettyVer T.pack bstrap++        -- download source tarball+        dlInfo <- (?? NoDownload (unsafeToTargetVersionReq tver) ghc (Just pfreq)) $ do+              (_, vi) <- preview (_GHCupDownloads % ix ghc % toolVersionsL % ix tver % revisionSpecL % mapLast) dls+              preview (viSourceDL % _Just) vi+        dl <- liftE $ downloadCached dlInfo Nothing++        -- unpack+        tmpUnpack <- lift mkGhcupTmpDir+        liftE $ cleanUpOnError tmpUnpack (unpackToDir (fromGHCupPath tmpUnpack) dl)+        liftE $ catchWarn $ lEM @_ @'[ProcessError] $ darwinNotarization _rPlatform $ fromGHCupPath tmpUnpack++        workdir <- maybe (pure tmpUnpack)+                         (liftE . intoSubdir tmpUnpack)+                         (view dlSubdir dlInfo)+        liftE $ applyAnyPatch patches (fromGHCupPath workdir)++        ov <- case vps of+                Just vps' -> fmap Just $ expandVersionPattern (Just ver) "" "" "" "" vps'+                Nothing   -> pure Nothing++        pure (workdir, tmpUnpack, Just (TargetVersion crossTarget ver), ov)++      RemoteDist uri -> do+        lift $ logDebug $ "Requested to compile (from uri): " <> T.pack (show uri)++        -- download source tarball+        tmpDownload <- lift withGHCupTmpDir+        tmpUnpack <- lift mkGhcupTmpDir+        tar <- liftE $ download uri Nothing Nothing Nothing (fromGHCupPath tmpDownload) Nothing False+        (bf, ver) <- liftE $ cleanUpOnError @'[UnknownArchive, ArchiveResult, ProcessError] tmpUnpack $ do+          liftE $ unpackToDir (fromGHCupPath tmpUnpack) tar+          let regex = [s|^(.*/)*boot$|] :: B.ByteString+          [bootFile] <- liftIO $ findFilesDeep+            tmpUnpack+            (makeRegexOpts compExtended+                           execBlank+                           regex+            )+          ver <- liftE $ catchAllE @_ @'[ProcessError, ParseError, NotFoundInPATH] @'[] (\_ -> pure Nothing) $ fmap Just $ getGHCVer+            (appendGHCupPath tmpUnpack (takeDirectory bootFile))+          pure (bootFile, ver)++        let workdir = appendGHCupPath tmpUnpack (takeDirectory bf)++        ov <- case vps of+                Just vps' -> fmap Just $ expandVersionPattern ver "" "" "" "" vps'+                Nothing   -> pure Nothing++        let tver = TargetVersion crossTarget <$> ver+        pure (workdir, tmpUnpack, tver, ov)++      -- clone from git+      GitDist GitBranch{..} -> do+        tmpUnpack <- lift mkGhcupTmpDir+        let git args = execLogged "git" ("--no-pager":args) (Just $ fromGHCupPath tmpUnpack) "git" Nothing+        (ver, ov) <- cleanUpOnError tmpUnpack $ reThrowAll @_ @'[PatchFailed, ProcessError, NotFoundInPATH, DigestError, ContentLengthError, DownloadFailed, GPGError] DownloadFailed $ do+          let rep = fromMaybe "https://gitlab.haskell.org/ghc/ghc.git" repo+          lift $ logInfo $ "Fetching git repo " <> T.pack rep <> " at ref " <> T.pack ref <> " (this may take a while)"+          lEM $ git [ "init" ]+          lEM $ git [ "remote"+                    , "add"+                    , "origin"+                    , fromString rep ]++          -- figure out if we can do a shallow clone+          remoteBranches <- catchE @ProcessError @'[PatchFailed, ProcessError, NotFoundInPATH, DigestError, ContentLengthError, DownloadFailed, GPGError] @'[PatchFailed, NotFoundInPATH, DigestError, DownloadFailed, GPGError] (\(_ :: ProcessError) -> pure [])+              $ fmap processBranches $ gitOut ["ls-remote", "--heads", "origin"] (fromGHCupPath tmpUnpack)+          let shallow_clone+                | isCommitHash ref                     = True+                | fromString ref `elem` remoteBranches = True+                | otherwise                            = False+          lift $ logDebug $ "Shallow clone: " <> T.pack (show shallow_clone)++          -- fetch+          let fetch_args+                | shallow_clone = ["fetch", "--depth", "1", "--quiet", "origin", fromString ref]+                | otherwise     = ["fetch", "--tags",       "--quiet", "origin"                ]+          lEM $ git fetch_args++          -- initial checkout+          lEM $ git [ "checkout", fromString ref ]++          -- gather some info+          git_describe <- if shallow_clone+                          then pure Nothing+                          else fmap Just $ liftE $ gitOut ["describe", "--tags"] (fromGHCupPath tmpUnpack)+          chash <- liftE $ gitOut ["rev-parse", "HEAD" ] (fromGHCupPath tmpUnpack)+          branch <- liftE $ gitOut ["rev-parse", "--abbrev-ref", "HEAD" ] (fromGHCupPath tmpUnpack)++          -- clone submodules+          lEM $ git [ "submodule", "update", "--init", "--depth", "1" ]++          -- apply patches+          liftE $ applyAnyPatch patches (fromGHCupPath tmpUnpack)++          -- bootstrap+          ver <- liftE $ catchAllE @_ @'[ProcessError, ParseError, NotFoundInPATH] @'[] (\_ -> pure Nothing) $ fmap Just $ getGHCVer+            tmpUnpack+          liftE $ catchWarn $ lEM @_ @'[ProcessError] $ darwinNotarization _rPlatform (fromGHCupPath tmpUnpack)+          lift $ logInfo $ "Examining git ref " <> T.pack ref <> "\n  " <>+                           "GHC version (from Makefile): " <> T.pack (show (prettyVer <$> ver)) <>+                           (if not shallow_clone then "\n  " <> "'git describe' output: " <> fromJust git_describe else mempty) <>+                           (if isCommitHash ref then mempty else "\n  " <> "commit hash: " <> chash)+          liftIO $ threadDelay 5000000 -- give the user a sec to intervene++          ov <- case vps of+                  Just vps' -> fmap Just $ expandVersionPattern+                                             ver+                                             (take 7 $ T.unpack chash)+                                             (T.unpack chash)+                                             (maybe "" T.unpack git_describe)+                                             (T.unpack branch)+                                             vps'+                  Nothing -> pure Nothing++          pure (ver, ov)++        let tver = TargetVersion crossTarget <$> ver+        pure (tmpUnpack, tmpUnpack, tver, ov)+    -- the version that's installed may differ from the+    -- compiled version, so the user can overwrite it+    installVer <- if | Just ov'   <- ov   -> pure (TargetVersion crossTarget ov')+                     | Just tver' <- tver -> pure tver'+                     | otherwise          -> fail "No GHC version given and couldn't detect version. Giving up..."++    let rev = fromMaybe 0 $ preview (_GHCupDownloads % ix ghc % toolVersionsL % ix installVer % revisionSpecL % mapLast % _1) dls++    alreadyInstalled <- lift $ isInstalled ghc installVer+    alreadySet <- liftE $ isSet ghc installVer++    when (isJust alreadyInstalled) $ do+      case installDir of+        IsolateDir isoDir ->+          lift $ logWarn $ "GHC " <> T.pack (prettyShow installVer) <> " already installed. Isolate installing to " <> T.pack isoDir+        GHCupInternal ->+          lift $ logWarn $ "GHC " <> T.pack (prettyShow installVer) <> " already installed. Will overwrite existing version."+      lift $ logWarn+        "...waiting for 10 seconds before continuing, you can still abort..."+      liftIO $ threadDelay 10000000 -- give the user a sec to intervene++    ghcdir <- case installDir of+      IsolateDir isoDir -> pure $ IsolateDirResolved isoDir+      GHCupInternal     -> GHCupDir <$> lift (ghcupGHCDir installVer)++    mBindist <- liftE $ runBuildAction+      tmpUnpack+      (do+        -- prefer 'tver', because the real version carries out compatibility checks+        -- we don't want the user to do funny things with it+        let doHadrian = Just <$> compileHadrianBindist (fromMaybe installVer tver) (fromGHCupPath workdir) ghcdir+            doMake    = compileMakeBindist (fromMaybe installVer tver) (fromGHCupPath workdir) ghcdir+        case buildSystem of+          Just Hadrian -> do+            lift $ logInfo "Requested to use Hadrian"+            liftE doHadrian+          Just Make -> do+            lift $ logInfo "Requested to use Make"+            doMake+          Nothing -> do+            supportsHadrian <- liftE $ catchE @HadrianNotFound @'[HadrianNotFound] @'[] (\_ -> return False)+                                 $ fmap (const True)+                                 $ findHadrianFile (fromGHCupPath workdir)+            if supportsHadrian+            then do+              lift $ logInfo "Detected Hadrian"+              liftE doHadrian+            else do+              lift $ logInfo "Detected Make"+              doMake+      )++    case installDir of+      GHCupInternal ->+        -- only remove old ghc in regular installs+        when (isJust alreadyInstalled) $ do+          lift $ logInfo "Deleting existing installation"+          liftE $ rmToolVersion ghc installVer++      _ -> pure ()++    let toolDesc = preview (_GHCupDownloads % ix ghc % toolDetails % _Just) dls++    let trev = TargetVersionRev installVer rev+    case mBindist of+      Just bindist -> do+        spec <- liftE $ compileInstallSpec bindist installVer+        cSize <- liftIO $ getFileSize bindist+        cDigest <- liftIO $ getFileDigest bindist+        liftE $ void $ installPackedBindist ghc toolDesc bindist+                                 (DownloadInfo {+                                   _dlUri = "file:" <> T.pack bindist+                                 , _dlSubdir = Just $ RegexDir "ghc-.*"+                                 , _dlHash = cDigest+                                 , _dlCSize = Just cSize+                                 , _dlOutput = Nothing+                                 , _dlTag = Nothing+                                 , _dlInstallSpec = Just (toInstallationInputSpec spec)+                                 })+                                 ghcdir+                                 trev+                                 False       -- not a force install, since we already overwrite when compiling.+                                 aargs+                                 installTargets+      -- for old Make cross installations we don't get a bindist,+      -- so this needs to be done manually+      Nothing -> do+        spec <- liftE $ compileInstallSpec' (fromInstallDir ghcdir </> "bin") installVer+        let dlInfo = (DownloadInfo {+                       _dlUri = ""+                     , _dlSubdir = Just $ RegexDir "ghc-.*"+                     , _dlHash = ""+                     , _dlCSize = Nothing+                     , _dlOutput = Nothing+                     , _dlTag = Nothing+                     , _dlInstallSpec = Just (toInstallationInputSpec spec)+                     })+        lift $ recordInstallationInfo ghcdir ghc toolDesc trev dlInfo spec++    case installDir of+      -- set and make symlinks for regular (non-isolated) installs+      GHCupInternal -> do+        symSpec <- liftE $ getSymlinkSpec' ghc installVer+        Dirs {..} <- lift getDirs+        liftE $ symlinkBinaries ghcdir symSpec (GHCupBinDir binDir) ghc installVer+        -- restore+        when (isJust alreadySet) $ liftE $ void $ setToolVersion ghc installVer++      _ -> pure ()++    pure installVer++ where+  -- Infer the installation spec from the binary directory+  compileInstallSpec' ::+    ( MonadIOish m+    , MonadReader env m+    , HasPlatformReq env+    )+    => FilePath                   -- ^ Binary dir+    -> TargetVersion+    -> Excepts '[ UnknownArchive+                , ArchiveResult+                ] m InstallationSpecResolved+  compileInstallSpec' bindir installVer = do+    pfreq <- lift getPlatformReq+    let pred' f = not (null f) && not (prettyVer (_tvVersion installVer) `T.isSuffixOf` T.pack f)+    files <- liftIO $ listDirectoryFiles bindir+    let binaries = filter pred' . fmap takeFileName $ files+        -- ghcup whereis picks the first binary, so we need to ensure 'ghc' is at the front+        binariesSorted = nub (maybe id (\(T.unpack -> t) a -> t <> "-" <> a) (_tvTarget installVer) "ghc" <.> exeExt:binaries)+    pure $ (defaultGHCInstallSpec pfreq installVer) { _isExeSymLinked = syml binariesSorted }+   where+    syml binaries =+      (\b -> SymlinkSpec (b <.> exeExt)+                         (takeFileName b <> "-${PKGVER}" <.> exeExt)+                         True+                         (Just $ takeFileName b <.> exeExt)+      ) . (\b -> "bin" Posix.</> b) <$> binaries++  -- Infer the installation spec from the tarball+  compileInstallSpec ::+    ( MonadIOish m+    , MonadReader env m+    , HasPlatformReq env+    )+    => FilePath                   -- ^ archive path+    -> TargetVersion+    -> Excepts '[ UnknownArchive+                , ArchiveResult+                ] m InstallationSpecResolved+  compileInstallSpec tarball installVer = do+    pfreq <- lift getPlatformReq+    archiveFiles <- liftE $ getArchiveFiles tarball+    let pred' f = not (null f) && not (prettyVer (_tvVersion installVer) `T.isSuffixOf` T.pack f)+    let binaries = filter pred' . fmap takeFileName . filter ("*/bin/*" ?==) $ archiveFiles+        -- ghcup whereis picks the first binary, so we need to ensure 'ghc' is at the front+        binariesSorted = nub (maybe id (\(T.unpack -> t) a -> t <> "-" <> a) (_tvTarget installVer) "ghc" <.> exeExt:binaries)+    pure $ (defaultGHCInstallSpec pfreq installVer) { _isExeSymLinked = syml binariesSorted }+   where+    syml binaries =+      (\b -> SymlinkSpec (b <.> exeExt)+                         (takeFileName b <> "-${PKGVER}" <.> exeExt)+                         True+                         (Just $ takeFileName b <.> exeExt)+      ) . (\b -> "bin" Posix.</> b) <$> binaries++  getGHCVer :: ( MonadReader env m+               , HasSettings env+               , HasDirs env+               , HasLog env+               , MonadIOish m+               )+            => GHCupPath+            -> Excepts '[ProcessError, ParseError, NotFoundInPATH] m Version+  getGHCVer tmpUnpack = do+    liftE $ execWithWrapper "python3" ["./boot"] (Just $ fromGHCupPath tmpUnpack) "ghc-bootstrap" Nothing+    liftE $ configureWithGhcBoot Nothing [] (Just $ fromGHCupPath tmpUnpack) "ghc-bootstrap"+    let versionFile = fromGHCupPath tmpUnpack </> "VERSION"+    hasVersionFile <- liftIO $ doesFileExist versionFile+    if hasVersionFile+    then do+      lift $ logDebug "Detected VERSION file, trying to extract"+      contents <- liftIO $ readFile versionFile+      either (throwE . ParseError . show) pure . MP.parse version' "" . T.pack . stripNewlineEnd $ contents+    else do+      lift $ logDebug "Didn't detect VERSION file, trying to extract via legacy 'make'"+      CapturedProcess {..} <- lift $ makeOut+        ["show!", "--quiet", "VALUE=ProjectVersion" ] (Just $ fromGHCupPath tmpUnpack)+      case _exitCode of+        ExitSuccess -> either (throwE . ParseError . show) pure . MP.parse ghcProjectVersion "" . T.pack . stripNewlineEnd . T.unpack . decUTF8Safe' $ _stdOut+        ExitFailure c -> throwE $ NonZeroExit c "make" ["show!", "--quiet", "VALUE=ProjectVersion" ]++  defaultConf =+    let cross_mk = $(LitE . StringL <$> (qAddDependentFile "data/build_mk/cross" >> runIO (readFile "data/build_mk/cross")))+        default_mk = $(LitE . StringL <$> (qAddDependentFile "data/build_mk/default" >> runIO (readFile "data/build_mk/default")))+    in case crossTarget of+         Just _ -> cross_mk+         _      -> default_mk++  compileHadrianBindist :: ( MonadReader env m+                           , HasDirs env+                           , HasSettings env+                           , HasPlatformReq env+                           , HasLog env+                           , MonadIOish m+                           )+                        => TargetVersion+                        -> FilePath+                        -> InstallDirResolved+                        -> Excepts+                             '[ FileDoesNotExistError+                              , HadrianNotFound+                              , InvalidBuildConfig+                              , PatchFailed+                              , ProcessError+                              , NotFoundInPATH+                              , CopyError]+                             m+                             FilePath  -- ^ output path of bindist+  compileHadrianBindist tver workdir ghcdir = do+    liftE $ configureBindist tver workdir ghcdir++    lift $ logInfo $ "Building GHC version " <> tVerToText tver <> " (this may take a while)..."+    hadrian_build <- liftE $ findHadrianFile workdir+    hEnv <- case hghc of+              Nothing -> pure Nothing+              Just hghc' -> do+                cEnv <- Map.fromList <$> liftIO getEnvironment+                ghc' <- liftE $ resolveGHC hghc'+                pure . Just . Map.toList . Map.insert "GHC" ghc' $ cEnv+++    liftE $ execWithWrapper hadrian_build+                          ( maybe [] (\j  -> ["-j" <> show j]         ) jobs+                         ++ maybe [] (\bf -> ["--flavour=" <> bf]) buildFlavour+                         ++ ["binary-dist"]+                          )+                          (Just workdir) "ghc-make"+                          hEnv+    [tar] <- liftIO $ findFiles+      (workdir </> "_build" </> "bindist")+      (makeRegexOpts compExtended+                     execBlank+                     ([s|^ghc-.*\.tar\..*$|] :: ByteString)+      )+    liftE $ copyBindist tver tar (workdir </> "_build" </> "bindist")++  findHadrianFile :: (MonadIO m)+                  => FilePath+                  -> Excepts+                       '[HadrianNotFound]+                       m+                       FilePath+  findHadrianFile workdir = do+    let possible_files = if isWindows+                         then ((workdir </> "hadrian") </>) <$> ["build.bat"]+                         else ((workdir </> "hadrian") </>) <$> ["build", "build.sh"]+    exists <- forM possible_files (\f -> liftIO (doesFileExist f) <&> (,f))+    case filter fst exists of+      []         -> throwE HadrianNotFound+      ((_, x):_) -> pure x++  compileMakeBindist :: ( MonadReader env m+                        , HasDirs env+                        , HasSettings env+                        , HasPlatformReq env+                        , MonadThrow m+                        , MonadCatch m+                        , HasLog env+                        , MonadIO m+                        , MonadFail m+                        , MonadMask m+                        , MonadUnliftIO m+                        , MonadResource m+                        )+                     => TargetVersion+                     -> FilePath+                     -> InstallDirResolved+                     -> Excepts+                          '[ FileDoesNotExistError+                           , HadrianNotFound+                           , InvalidBuildConfig+                           , PatchFailed+                           , ProcessError+                           , NotFoundInPATH+                           , MergeFileTreeError+                           , CopyError]+                          m+                       (Maybe FilePath)  -- ^ output path of bindist, None for cross+  compileMakeBindist tver workdir ghcdir = do+    liftE $ configureBindist tver workdir ghcdir++    case mbuildConfig of+      Just bc -> liftIOException+        doesNotExistErrorType+        (FileDoesNotExistError bc)+        (liftIO $ copyFile bc (build_mk workdir) False)+      Nothing ->+        liftIO $ T.writeFile (build_mk workdir) (addBuildFlavourToConf defaultConf)++    liftE $ checkBuildConfig (build_mk workdir)++    lift $ logInfo $ "Building GHC version " <> tVerToText tver <> " (this may take a while)..."+    liftE $ makeWithWrapper (maybe [] (\j -> ["-j" <> fS (show j)]) jobs) (Just workdir) "ghc-make" Nothing++    if | isCross tver -> do -- this is effectively legacy too (and does not install a .spec)+          lift $ logInfo "Installing cross toolchain..."+          tmpInstallDest <- lift withGHCupTmpDir+          liftE $ makeWithWrapper ["DESTDIR=" <> fromGHCupPath tmpInstallDest, "install"] (Just workdir) "ghc-make" Nothing+          liftE $ mergeGHCFileTree (tmpInstallDest `appendGHCupPath` dropDrive (fromInstallDir ghcdir)) ghcdir tver True+          pure Nothing+       | otherwise -> do+          lift $ logInfo "Creating bindist..."+          liftE $ makeWithWrapper ["binary-dist"] (Just workdir) "ghc-make" Nothing+          [tar] <- liftIO $ findFiles+            workdir+            (makeRegexOpts compExtended+                           execBlank+                           ([s|^ghc-.*\.tar\..*$|] :: ByteString)+            )+          liftE $ fmap Just $ copyBindist tver tar workdir++  build_mk workdir = workdir </> "mk" </> "build.mk"++  copyBindist :: ( MonadReader env m+                 , HasDirs env+                 , HasSettings env+                 , HasPlatformReq env+                 , MonadIO m+                 , MonadThrow m+                 , MonadCatch m+                 , HasLog env+                 )+              => TargetVersion+              -> FilePath           -- ^ tar file+              -> FilePath           -- ^ workdir+              -> Excepts+                   '[CopyError]+                   m+                   FilePath+  copyBindist tver tar workdir = do+    Dirs {..} <- lift getDirs+    pfreq <- lift getPlatformReq+    c       <- liftIO $ BL.readFile (workdir </> tar)+    cDigest <-+      fmap (T.take 8)+      . lift+      . throwEither+      . E.decodeUtf8'+      . B16.encode+      . SHA256.hashlazy+      $ c+    cTime <- liftIO getCurrentTime+    let tarName = makeValid ("ghc-"+                            <> T.unpack (tVerToText tver)+                            <> "-"+                            <> pfReqToString pfreq+                            <> "-"+                            <> iso8601Show cTime+                            <> "-"+                            <> T.unpack cDigest+                            <> ".tar"+                            <> takeExtension tar)+    let tarPath = fromGHCupPath cacheDir </> tarName+    copyFileE (workdir </> tar) tarPath False+    lift $ logInfo $ "Copied bindist to " <> T.pack tarPath+    pure tarPath++  checkBuildConfig :: (MonadReader env m, MonadCatch m, MonadIO m, HasLog env)+                   => FilePath+                   -> Excepts+                        '[FileDoesNotExistError, InvalidBuildConfig]+                        m+                        ()+  checkBuildConfig bc = do+    c <- liftIOException+           doesNotExistErrorType+           (FileDoesNotExistError bc)+           (liftIO $ B.readFile bc)+    let lines' = fmap T.strip . T.lines $ decUTF8Safe c++   -- for cross, we need Stage1Only+    case crossTarget of+      Just _ -> when ("Stage1Only = YES" `notElem` lines') $ throwE+        (InvalidBuildConfig+          [s|Cross compiling needs to be a Stage1 build, add "Stage1Only = YES" to your config!|]+        )+      _ -> pure ()++    forM_ buildFlavour $ \bf ->+      when (T.pack ("BuildFlavour = " <> bf) `notElem` lines') $ do+        lift $ logWarn $ "Customly specified build config overwrites --flavour=" <> T.pack bf <> " switch! Waiting 5 seconds..."+        liftIO $ threadDelay 5000000++  addBuildFlavourToConf bc = case buildFlavour of+    Just bf -> "BuildFlavour = " <> T.pack bf <> "\n" <> bc+    Nothing -> bc++  isCross :: TargetVersion -> Bool+  isCross = isJust . _tvTarget+++  configureBindist :: ( MonadReader env m+                      , HasDirs env+                      , HasSettings env+                      , HasPlatformReq env+                      , HasLog env+                      , MonadIOish m+                      )+                   => TargetVersion+                   -> FilePath+                   -> InstallDirResolved+                   -> Excepts+                        '[ FileDoesNotExistError+                         , InvalidBuildConfig+                         , PatchFailed+                         , ProcessError+                         , NotFoundInPATH+                         , CopyError+                         ]+                        m+                        ()+  configureBindist tver workdir (fromInstallDir -> ghcdir) = do+    PlatformRequest { .. } <- lift getPlatformReq+    lift $ logInfo [s|configuring build|]+    liftE $ configureWithGhcBoot (Just tver)+      (maybe mempty+                (\x -> ["--target=" <> T.unpack x])+                (_tvTarget tver)+      ++ ["--prefix=" <> ghcdir]+      ++ (if isWindows then ["--enable-tarballs-autodownload"] else [])+      -- https://github.com/haskell/ghcup-hs/issues/1032+      ++ ldOverride (_tvVersion tver) _rPlatform+      ++ aargs+      )+      (Just workdir)+      "ghc-conf"+    pure ()++  configureWithGhcBoot :: ( MonadReader env m+                          , HasSettings env+                          , HasDirs env+                          , HasLog env+                          , MonadIOish m+                          )+                       => Maybe TargetVersion+                       -> [String]         -- ^ args for configure+                       -> Maybe FilePath   -- ^ optionally chdir into this+                       -> FilePath         -- ^ log filename (opened in append mode)+                       -> Excepts '[ProcessError, NotFoundInPATH] m ()+  configureWithGhcBoot mtver args dir logf = do+    bghc <- liftE $ resolveGHC bstrap+    let execNew = execWithWrapper+                    "sh"+                    ("./configure" : ("GHC=" <> bghc) : args)+                    dir+                    logf+                    Nothing+        execOld = execWithWrapper+                   "sh"+                   ("./configure" : ("--with-ghc=" <> bghc) : args)+                   dir+                   logf+                   Nothing+    if | Just tver <- mtver+       , _tvVersion tver >= [vver|8.8.0|] -> liftE execNew+       | Nothing   <- mtver               -> liftE execNew -- need some default for git checkouts where we don't know yet+       | otherwise                        -> liftE execOld++  resolveGHC :: MonadIO m => Either Version FilePath -> Excepts '[NotFoundInPATH] m FilePath+  resolveGHC = \case+           Right g    -> pure g+           Left  bver -> do+             let ghc' = "ghc-" <> (T.unpack . prettyVer $ bver) <> exeExt+             -- https://gitlab.haskell.org/ghc/ghc/-/issues/24682+             makeAbsolute ghc'+++++    -------------+    --[ Other ]--+    -------------+++ldOverride ::  Version -> Platform -> [String]+ldOverride ver _plat+  | ver >= [vver|8.2.2|]+  = ["--disable-ld-override"]+  | otherwise+  = []++sanitizefGHCconfOptions :: MonadFail m => [String] -> m [String]+sanitizefGHCconfOptions args+  | "--prefix" `elem` fmap (takeWhile (/= '=')) args = fail "Don't explicitly set --prefix ...aborting"+  | otherwise = pure args+
+ lib/GHCup/Command/Compile/HLS.hs view
@@ -0,0 +1,473 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}++{-|+Module      : GHCup.Command.Compile.HLS+Description : GHCup compile HLS+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Command.Compile.HLS where++import GHCup.Builder+import GHCup.Command.Install.LowLevel+import GHCup.Download+import GHCup.Errors+import GHCup.Input.SymlinkSpec+import GHCup.Legacy.HLS               ( installHLSUnpackedLegacy )+import GHCup.Prelude+import GHCup.Prelude.Process+import GHCup.Prelude.String.QQ+import GHCup.Query.DB+import GHCup.Query.GHCupDirs+import GHCup.System.Cmd+import GHCup.System.Directory+import GHCup.Types+import GHCup.Types.Optics+import GHCup.Unpack++import Control.Applicative+import Control.Exception.Safe+import Control.Monad+#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Monad.Reader+import Control.Monad.Trans.Resource                 hiding ( throwM )+import Data.Either+import Data.List+import Data.Maybe+import Data.String                                  ( fromString )+import Data.Text                                    ( Text )+import Data.Variant.Excepts+import Data.Versions                                hiding ( patch )+import Distribution.PackageDescription.Parsec+import Distribution.Types.GenericPackageDescription+import Distribution.Types.PackageDescription+import Distribution.Types.PackageId+import Distribution.Types.Version                   hiding ( Version )+import Optics+import Prelude                                      hiding ( abs, writeFile )+import System.FilePath+import Text.Regex.Posix+import URI.ByteString++import qualified Data.ByteString    as B+import qualified Data.List.NonEmpty as NE+import qualified Data.Text          as T+++data HLSVer+  = SourceDist Version+  | GitDist GitBranch+  | HackageDist Version+  | RemoteDist URI+  deriving (Eq, Show)+++++compileHLS :: ( MonadMask m+              , MonadCatch m+              , MonadReader env m+              , HasDirs env+              , HasSettings env+              , HasPlatformReq env+              , HasGHCupInfo env+              , HasLog env+              , MonadResource m+              , MonadIO m+              , MonadUnliftIO m+              , MonadFail m+              )+           => HLSVer+           -> [Version]+           -> Maybe Int+           -> Maybe [VersionPattern]+           -> InstallDir+           -> Maybe (Either FilePath URI)+           -> Maybe URI+           -> Bool+           -> Maybe (Either FilePath [URI])  -- ^ patches+           -> [Text]                   -- ^ additional args to cabal install+           -> Excepts '[ NoDownload+                       , GPGError+                       , DownloadFailed+                       , DigestError+                       , ContentLengthError+                       , UnknownArchive+                       , TarDirDoesNotExist+                       , ArchiveResult+                       , BuildFailed+                       , NotInstalled+                       , URIParseError+                       ] m Version+compileHLS targetHLS ghcs jobs vps installDir cabalProject cabalProjectLocal updateCabal patches cabalArgs = do+  pfreq@PlatformRequest { .. } <- lift getPlatformReq+  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo+  let toolDesc = preview (_GHCupDownloads % ix hls % toolDetails % _Just) dls+  Dirs { .. } <- lift getDirs+++  when updateCabal $ reThrowAll @_ @'[ProcessError] DownloadFailed $ do+    lift $ logInfo "Updating cabal DB"+    liftE $ execWithWrapper "cabal" ["update"] (Just $ fromGHCupPath tmpDir) "cabal" Nothing++  (workdir, tmpUnpack, ver, rev, ov) <- case targetHLS of+    -- unpack from version tarball+    SourceDist ver -> do+      let tver = mkTVer ver+      lift $ logDebug $ "Requested to compile: " <> prettyVer ver++      -- download source tarball+      (rev, dlInfo) <- (?? NoDownload (unsafeToTargetVersionReq tver) hls (Just pfreq)) $ do+            (rev, vi) <- preview (_GHCupDownloads % ix hls % toolVersionsL % ix tver % revisionSpecL % mapLast) dls+            dlInfo <- preview (viSourceDL % _Just) vi+            pure (rev, dlInfo)+      dl <- liftE $ downloadCached dlInfo Nothing++      -- unpack+      tmpUnpack <- lift mkGhcupTmpDir+      liftE $ cleanUpOnError tmpUnpack (unpackToDir (fromGHCupPath tmpUnpack) dl)+      liftE $ catchWarn $ lEM @_ @'[ProcessError] $ darwinNotarization _rPlatform (fromGHCupPath tmpUnpack)++      workdir <- maybe (pure tmpUnpack)+                       (liftE . intoSubdir tmpUnpack)+                       (view dlSubdir dlInfo)++      ov <- case vps of+              Just vps' -> fmap Just $ expandVersionPattern (Just ver) "" "" "" "" vps'+              Nothing   -> pure Nothing++      pure (workdir, tmpUnpack, ver, rev, ov)++    HackageDist ver -> do+      lift $ logDebug $ "Requested to compile (from hackage): " <> prettyVer ver++      -- download source tarball+      tmpUnpack <- lift mkGhcupTmpDir+      let hls' = "haskell-language-server-" <> T.unpack (prettyVer ver)+      reThrowAll @_ @'[ProcessError] DownloadFailed $ do+        -- unpack+        liftE $ execWithWrapper "cabal" ["unpack", hls'] (Just $ fromGHCupPath tmpUnpack) "cabal" Nothing++      let workdir = appendGHCupPath tmpUnpack hls'++      ov <- case vps of+              Just vps' -> fmap Just $ expandVersionPattern (Just ver) "" "" "" "" vps'+              Nothing   -> pure Nothing++      let rev = fromMaybe 0 $ preview (_GHCupDownloads % ix hls % toolVersionsL % ix (mkTVer ver) % revisionSpecL % mapLast % _1) dls+      pure (workdir, tmpUnpack, ver, rev, ov)++    RemoteDist uri -> do+      lift $ logDebug $ "Requested to compile (from uri): " <> T.pack (show uri)++      -- download source tarball+      tmpDownload <- lift withGHCupTmpDir+      tmpUnpack <- lift mkGhcupTmpDir+      tar <- liftE $ download uri Nothing Nothing Nothing (fromGHCupPath tmpDownload) Nothing False+      (cf, ver) <- liftE $ cleanUpOnError tmpUnpack $ do+        unpackToDir (fromGHCupPath tmpUnpack) tar+        let regex = [s|^(.*/)*haskell-language-server\.cabal$|] :: B.ByteString+        [cabalFile] <- liftIO $ findFilesDeep+          tmpUnpack+          (makeRegexOpts compExtended+                         execBlank+                         regex+          )+        ver <- getCabalVersion (fromGHCupPath tmpUnpack </> cabalFile)+        pure (cabalFile, ver)++      let workdir = appendGHCupPath tmpUnpack (takeDirectory cf)++      ov <- case vps of+              Just vps' -> fmap Just $ expandVersionPattern (Just ver) "" "" "" "" vps'+              Nothing   -> pure Nothing++      let rev = fromMaybe 0 $ preview (_GHCupDownloads % ix hls % toolVersionsL % ix (mkTVer ver) % revisionSpecL % mapLast % _1) dls+      pure (workdir, tmpUnpack, ver, rev, ov)++    -- clone from git+    GitDist GitBranch{..} -> do+      tmpUnpack <- lift mkGhcupTmpDir+      let git args = execLogged "git" ("--no-pager":args) (Just $ fromGHCupPath tmpUnpack) "git" Nothing+      cleanUpOnError tmpUnpack $ reThrowAll @_ @'[ProcessError] DownloadFailed $ do+        let rep = fromMaybe "https://github.com/haskell/haskell-language-server.git" repo+        lift $ logInfo $ "Fetching git repo " <> T.pack rep <> " at ref " <> T.pack ref <> " (this may take a while)"+        lEM $ git [ "init" ]+        lEM $ git [ "remote"+                  , "add"+                  , "origin"+                  , fromString rep ]++        -- figure out if we can do a shallow clone+        remoteBranches <- catchE @ProcessError @'[ProcessError] @'[] (\_ -> pure [])+            $ fmap processBranches $ gitOut ["ls-remote", "--heads", "origin"] (fromGHCupPath tmpUnpack)+        let shallow_clone+              | gitDescribeRequested                 = False+              | isCommitHash ref                     = True+              | fromString ref `elem` remoteBranches = True+              | otherwise                            = False++        lift $ logDebug $ "Shallow clone: " <> T.pack (show shallow_clone)++        -- fetch+        let fetch_args+              | shallow_clone = ["fetch", "--depth", "1", "--quiet", "origin", fromString ref]+              | otherwise     = ["fetch", "--tags",       "--quiet", "origin"                ]+        lEM $ git fetch_args++        -- checkout+        lEM $ git [ "checkout", fromString ref ]++        -- gather some info+        git_describe <- if shallow_clone+                        then pure Nothing+                        else fmap Just $ gitOut ["describe", "--tags"] (fromGHCupPath tmpUnpack)+        chash <- gitOut ["rev-parse", "HEAD" ] (fromGHCupPath tmpUnpack)+        branch <- gitOut ["rev-parse", "--abbrev-ref", "HEAD" ] (fromGHCupPath tmpUnpack)+        ver <- getCabalVersion (fromGHCupPath tmpUnpack </> "haskell-language-server.cabal")++        liftE $ catchWarn $ lEM @_ @'[ProcessError] $ darwinNotarization _rPlatform (fromGHCupPath tmpUnpack)++        ov <- case vps of+                Just vps' -> fmap Just $ expandVersionPattern+                                           (Just ver)+                                           (take 7 $ T.unpack chash)+                                           (T.unpack chash)+                                           (maybe "" T.unpack git_describe)+                                           (T.unpack branch)+                                           vps'+                Nothing -> pure Nothing++        lift $ logInfo $ "Examining git ref " <> T.pack ref <> "\n  " <>+                                    "HLS version (from cabal file): " <> prettyVer ver <>+                                    "\n  branch: " <> branch <>+                                    (if not shallow_clone then "\n  " <> "'git describe' output: " <> fromJust git_describe else mempty) <>+                                    (if isCommitHash ref then mempty else "\n  " <> "commit hash: " <> chash)++        let rev = fromMaybe 0 $ preview (_GHCupDownloads % ix hls % toolVersionsL % ix (mkTVer ver) % revisionSpecL % mapLast % _1) dls+        pure (tmpUnpack, tmpUnpack, ver, rev, ov)++  -- the version that's installed may differ from the+  -- compiled version, so the user can overwrite it+  installVer <- maybe (pure ver) pure ov++  liftE $ runBuildAction+    tmpUnpack+    (reThrowAll @_ @'[GPGError, DownloadFailed, DigestError, ContentLengthError, PatchFailed, ProcessError, FileAlreadyExistsError, CopyError, ParseError , MergeFileTreeError , MalformedInstallInfo, FileDoesNotExistError, NoInstallInfo] @'[BuildFailed] (BuildFailed $ fromGHCupPath workdir) $ do+      let tmpInstallDir = fromGHCupPath workdir </> "out"+      liftIO $ createDirRecursive' tmpInstallDir++      -- apply patches+      liftE $ applyAnyPatch patches (fromGHCupPath workdir)++      -- set up project files+      cp <- case cabalProject of+        Just (Left cp)+          | isAbsolute cp -> do+              copyFileE cp (fromGHCupPath workdir </> "cabal.project") False+              pure "cabal.project"+          | otherwise -> pure (takeFileName cp)+        Just (Right uri) -> do+          tmpUnpack' <- lift withGHCupTmpDir+          cp <- liftE $ download uri Nothing Nothing Nothing (fromGHCupPath tmpUnpack') (Just "cabal.project") False+          copyFileE cp (fromGHCupPath workdir </> "cabal.project") False+          pure "cabal.project"+        Nothing+          | HackageDist _ <- targetHLS -> do+              liftIO $ B.writeFile (fromGHCupPath workdir </> "cabal.project") "packages: ./"+              pure "cabal.project"+          | RemoteDist _ <- targetHLS -> do+              let cabalFile = fromGHCupPath workdir </> "cabal.project"+              liftIO $ whenM (not <$> doesFileExist cabalFile) $ B.writeFile cabalFile "packages: ./"+              pure "cabal.project"+          | otherwise -> pure "cabal.project"+      forM_ cabalProjectLocal $ \uri -> do+        tmpUnpack' <- lift withGHCupTmpDir+        cpl <- liftE $ download uri Nothing Nothing Nothing (fromGHCupPath tmpUnpack') (Just (cp <.> "local")) False+        copyFileE cpl (fromGHCupPath workdir </> cp <.> "local") False+      artifactDirs <- forM (sort ghcs) $ \ghc' -> do+        let ghcInstallDir = tmpInstallDir </> T.unpack (prettyVer ghc')+        liftIO $ createDirRecursive' tmpInstallDir+        lift $ logInfo $ "Building HLS " <> prettyVer installVer <> " for GHC version " <> prettyVer ghc'+        liftE $+          execWithWrapper "cabal" ( [ "v2-install"+                               , "-w"+                               , "ghc-" <> T.unpack (prettyVer ghc')+                               , "--install-method=copy"+                               ] +++                               maybe [] (\j -> ["--jobs=" <> show j]) jobs +++                               [ "--overwrite-policy=always"+                               , "--disable-profiling"+                               , "--disable-tests"+                               , "--installdir=" <> ghcInstallDir+                               , "--project-file=" <> cp+                               ] ++ fmap T.unpack cabalArgs ++ [+                                 "exe:haskell-language-server"+                               , "exe:haskell-language-server-wrapper"]+                             )+                             (Just $ fromGHCupPath workdir)+                             "cabal"+                             Nothing+        pure ghcInstallDir++      forM_ artifactDirs $ \artifactDir -> do+        logDebug $ "mv " <> T.pack (artifactDir </> "haskell-language-server" <.> exeExt) <> " "+                         <> T.pack (tmpInstallDir </> "haskell-language-server-" <> takeFileName artifactDir <.> exeExt)+        liftIO $ renameFile (artifactDir </> "haskell-language-server" <.> exeExt)+          (tmpInstallDir </> "haskell-language-server-" <> takeFileName artifactDir <.> exeExt)+        logDebug $ "mv " <> T.pack (artifactDir </> "haskell-language-server-wrapper" <.> exeExt) <> " "+                         <> T.pack (tmpInstallDir </> "haskell-language-server-wrapper" <.> exeExt)+        liftIO $ renameFile (artifactDir </> "haskell-language-server-wrapper" <.> exeExt)+          (tmpInstallDir </> "haskell-language-server-wrapper" <.> exeExt)+++      installDirResolved <- case installDir of+                              IsolateDir isoDir -> pure $ IsolateDirResolved isoDir+                              GHCupInternal -> GHCupDir <$> lift (toolInstallDestination hls (mkTVer installVer))++      runE (getInstallMetadata hls (mkTVer installVer)) >>= \case+        VRight metadata -> do+          destdir <- lift withGHCupTmpDir+          liftE $ addAdHocBinaries (Just metadata) toolDesc tmpInstallDir installDirResolved destdir (VersionRev installVer rev) True+        VLeft (V (FileDoesNotExistError _)) -> do+          inst <- lift $ isInstalled hls (mkTVer installVer)+          if isJust inst+          then liftE $ installHLSUnpackedLegacy tmpInstallDir (GHCupBinDir binDir) installVer True+          else do+            destdir <- lift withGHCupTmpDir+            liftE $ addAdHocBinaries Nothing toolDesc tmpInstallDir installDirResolved destdir (VersionRev installVer rev) True+        VLeft (V (ParseError pe)) -> liftE $ throwE @_ @'[ParseError] (ParseError pe)+        VLeft v -> lift $ fail (prettyHFError v)+    )++  pure installVer+ where+  gitDescribeRequested = maybe False (GitDescribe `elem`) vps++  adHocInstallationSpec :: [FilePath]         -- ^ no .exe extension+                        -> InstallationSpecResolved+  adHocInstallationSpec hlsExes =+    InstallationSpec {+      _isExeRules =+        hlsExes <&> (\exe -> InstallFileRule { _ibrInstallSource = exe <.> exeExt+                                             , _ibrInstallDest = Just $ "bin" </> exe <.> exeExt+                                             })+    , _isDataRules = []+    , _isConfigure = Nothing+    , _isMake = Nothing+    , _isExeSymLinked = hlsExes <&> \hlsExe ->+        if hlsExe == "haskell-language-server-wrapper"+        then SymlinkSpec { _slTarget        = "bin" </> hlsExe <.> exeExt+                         , _slLinkName      = hlsExe <> "-${PKGVER}" <.> exeExt+                         , _slPVPMajorLinks = False+                         , _slSetName       = Just (hlsExe <.> exeExt)+                         }+        else SymlinkSpec { _slTarget        = "bin" </> hlsExe <.> exeExt+                         , _slLinkName      = hlsExe <> "~${PKGVER}" <.> exeExt+                         , _slPVPMajorLinks = False+                         , _slSetName       = Just (hlsExe <.> exeExt)+                         }+    , _isPreserveMtimes = False+    }++  addAdHocBinaries :: forall m env .+    ( HasLog env+    , HasDirs env+    , HasSettings env+    , HasPlatformReq env+    , MonadReader env m+    , MonadIOish m+    )+    => Maybe InstallMetadata+    -> Maybe ToolDescription+    -> FilePath+    -> InstallDirResolved   -- ^ Path to install to+    -> GHCupPath            -- ^ DESTDIR+    -> VersionRev+    -> Bool+    -> Excepts '[ CopyError+                , MergeFileTreeError+                , ParseError+                , MalformedInstallInfo+                , NoInstallInfo+                , ProcessError+                ] m ()+  addAdHocBinaries mMetadata toolDesc workdir installDest tmpInstallDest VersionRev{..} forceInstall = do+    let tver = mkTVer _vrVersion+    binaries <- liftIO $ listDirectoryFiles workdir+    let spec = adHocInstallationSpec (dropSuffix exeExt <$> binaries)++    logDebug $ T.pack (show spec)+    logDebug "Install into tmp dir as per the spec"+    liftE $ installTheSpec (toInstallationInputSpec spec) workdir installDest tmpInstallDest [] Nothing forceInstall++    logDebug "Merge to filesystem"+    liftE $ mergeToFileSystem hls tver installDest tmpInstallDest (_isPreserveMtimes spec) forceInstall True+++    case installDir of+      -- set and make symlinks for regular (non-isolated) installs+      GHCupInternal -> do+        logDebug "Symlink binaries"+        Dirs {..} <- lift getDirs+        parsedSymlinkSpec <- forM (_isExeSymLinked spec) (liftE . parseSymlinkSpec (_tvVersion tver))+        liftE $ symlinkBinaries installDest parsedSymlinkSpec (GHCupBinDir binDir) hls tver++        -- write InstallationInfo to the disk+        logDebug "Writing installation info to disk"+        case mMetadata of+          (Just (InstallMetadata {..})) -> do+            lift $ recordInstallationInfo installDest hls toolDesc (TargetVersionRev tver _imRevision) _imDownloadInfo (manipulateSpec _imResolvedInstallSpec spec)+          Nothing -> do+            let dlInfo = DownloadInfo "" Nothing "" Nothing Nothing Nothing (Just $ toInstallationInputSpec spec)+            lift $ recordInstallationInfo installDest hls toolDesc (TargetVersionRev tver _vrRev) dlInfo spec+      _ -> pure ()++    pure ()+   where+    -- we install ad-hoc binaries and now need to adjust the exeSymLinked part+    -- so that uninstallation removes the additional symlinks+    manipulateSpec :: InstallationSpecResolved -> InstallationSpecResolved -> InstallationSpecResolved+    manipulateSpec origSpec adhocSpec =+      let oldSymls = _isExeSymLinked origSpec+          newSymls = _isExeSymLinked adhocSpec+      in origSpec { _isExeSymLinked = merge oldSymls newSymls }+     where+      merge :: [SymlinkSpec String] -> [SymlinkSpec String] -> [SymlinkSpec String]+      merge old new = nub (old <> new)++++    ---------------+    --[ Removal ]--+    ---------------++++getCabalVersion :: (MonadIO m, MonadFail m) => FilePath -> m Version+getCabalVersion fp = do+  contents <- liftIO $ B.readFile fp+  gpd <- case parseGenericPackageDescriptionMaybe contents of+           Nothing -> fail $ "could not parse cabal file: " <> fp+           Just r  -> pure r+  let tver = (\c -> Version Nothing c Nothing Nothing)+           . Chunks+           . NE.fromList+           . fmap (Numeric . fromIntegral)+           . versionNumbers+           . pkgVersion+           . package+           . packageDescription+           $ gpd+  pure tver
+ lib/GHCup/Command/DebugInfo.hs view
@@ -0,0 +1,69 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}++{-|+Module      : GHCup.Command.DebugInfo+Description : GHCup installation functions+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable++This module contains the main functions that correspond+to the command line interface, like installation, listing versions+and so on.++These are the entry points.+-}+module GHCup.Command.DebugInfo where+++import GHCup.Errors+import GHCup.Hardcoded.URLs+import GHCup.Prelude+import GHCup.Query.System+import GHCup.Types+import GHCup.Types.JSON+    ()+import GHCup.Types.Optics++import Control.Applicative+import Control.Exception.Safe+import Control.Monad+#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Monad.Reader+import Data.Variant.Excepts+import Prelude                      hiding ( abs, writeFile )+++++    ------------------+    --[ Debug info ]--+    ------------------+++getDebugInfo :: ( MonadFail m+                , MonadReader env m+                , HasDirs env+                , HasLog env+                , MonadCatch m+                , MonadIO m+                )+             => Excepts+                  '[NoCompatiblePlatform , NoCompatibleArch , DistroNotFound]+                  m+                  DebugInfo+getDebugInfo = do+  diDirs <- lift getDirs+  let diChannels = fmap (\c -> (c, channelURL c)) [minBound..maxBound]+  let diShimGenURL = shimGenURL+  diArch         <- lE getArchitecture+  diPlatform     <- liftE getPlatform+  pure $ DebugInfo { .. }
+ lib/GHCup/Command/GC.hs view
@@ -0,0 +1,204 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}++{-|+Module      : GHCup.Command.GC+Description : GHCup gc+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Command.GC where+++import GHCup.Command.List+import GHCup.Command.Rm+import GHCup.Errors+import GHCup.Legacy.HLS+import GHCup.Legacy.Utils+import GHCup.Prelude+import GHCup.Prelude.String.QQ+import GHCup.Query.DB+import GHCup.Query.GHCupDirs+import GHCup.Query.Metadata+import GHCup.System.Directory+import GHCup.Types+import GHCup.Types.Optics++import Control.Applicative+import Control.Exception.Safe+import Control.Monad+#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Monad.Reader+import Control.Monad.Trans.Resource hiding ( throwM )+import Data.ByteString              ( ByteString )+import Data.Foldable.WithIndex+import Data.List+import Data.Maybe+import Data.Variant.Excepts+import Optics+import Prelude                      hiding ( abs, writeFile )+import System.FilePath+import Text.Regex.Posix++import qualified Data.Text as T++++    --------------------------+    --[ Garbage collection ]--+    --------------------------+++rmOldGHC :: ( MonadReader env m+            , HasGHCupInfo env+            , HasPlatformReq env+            , HasDirs env+            , HasLog env+            , MonadIOish m+            )+         => Excepts '[NotInstalled, UninstallFailed, ParseError, MalformedInstallInfo] m ()+rmOldGHC = do+  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo+  let oldGHCs = toListOf (_GHCupDownloads % ix ghc % toolVersions % getTaggedL Old % to fst) dls+  ghcs <- lift $ getInstalledVersions' ghc+  forM_ (_tvrTargetVer <$> ghcs) $ \ghcVer -> when (ghcVer `elem` oldGHCs) $ rmToolVersion ghc ghcVer+++rmUnsetTools :: ( MonadReader env m+                , HasGHCupInfo env+                , HasPlatformReq env+                , HasDirs env+                , HasLog env+                , MonadIO m+                , MonadFail m+                , MonadMask m+                , MonadUnliftIO m+                )+             => Excepts '[NotInstalled, UninstallFailed, ParseError, MalformedInstallInfo] m ()+rmUnsetTools = do+  vers <- liftE $ listVersions Nothing [ListInstalled True, ListSet False] ShowUpdates False True (Nothing, Nothing)+  iforM_ vers $ \tool (_, ls) -> forM_ ls $ \ListResult{..} -> liftE $ rmToolVersion tool (TargetVersion lCross lVer)+++rmProfilingLibs :: ( MonadReader env m+                   , HasDirs env+                   , HasLog env+                   , MonadIO m+                   , MonadFail m+                   , MonadMask m+                   , MonadUnliftIO m+                   )+                => m ()+rmProfilingLibs = do+  ghcs <- getInstalledVersions' ghc++  let regexes :: [ByteString]+      regexes = [[s|.*_p\.a$|], [s|.*\.p_hi$|]]++  forM_ regexes $ \regex ->+    forM_ (_tvrTargetVer <$> ghcs) $ \ghc' -> do+      d <- ghcupGHCDir ghc'+      -- TODO: audit findFilesDeep+      matches <- liftIO $ handleIO (\_ -> pure []) $ findFilesDeep+        d+        (makeRegexOpts compExtended+                       execBlank+                       regex+        )+      forM_ matches $ \m -> do+        let p = fromGHCupPath d </> m+        logDebug $ "rm " <> T.pack p+        rmFile p++++rmShareDir :: ( MonadReader env m+              , HasDirs env+              , HasLog env+              , MonadIO m+              , MonadFail m+              , MonadMask m+              , MonadUnliftIO m+              )+           => m ()+rmShareDir = do+  ghcs <- getInstalledVersions' ghc+  forM_ (_tvrTargetVer <$> ghcs) $ \ghc' -> do+    d <- ghcupGHCDir ghc'+    let p = d `appendGHCupPath` "share"+    logDebug $ "rm -rf " <> T.pack (fromGHCupPath p)+    rmPathForcibly p+++rmHLSNoGHC :: ( MonadReader env m+              , HasDirs env+              , HasLog env+              , MonadIO m+              , MonadMask m+              , MonadFail m+              , MonadUnliftIO m+              )+           => Excepts '[NotInstalled, UninstallFailed] m ()+rmHLSNoGHC = do+  Dirs {..} <- getDirs+  ghcs <- lift $ getInstalledVersions' ghc+  hlses <- lift $ getInstalledVersions hls Nothing -- TODO: we don't support cross HLS+  forM_ (_vrVersion <$> hlses) $ \hls' -> do+    hlsGHCs <- fmap mkTVer <$> hlsGHCVersions' hls'+    let candidates = filter (`notElem` (_tvrTargetVer <$> ghcs)) hlsGHCs+    if (length hlsGHCs - length candidates) <= 0+    then rmHLSVer hls'+    else+      -- TODO: uff+      forM_ candidates $ \ghc' -> do+        bins1 <- fmap (binDir </>) <$> hlsServerBinaries hls' (Just $ _tvVersion ghc')+        bins2 <- ifM (isLegacyHLS hls') (pure []) $ do+          shs <- hlsInternalServerScripts hls' (Just $ _tvVersion ghc')+          bins <- hlsInternalServerBinaries hls' (Just $ _tvVersion ghc')+          libs <- hlsInternalServerLibs hls' (_tvVersion ghc')+          pure (shs ++ bins ++ libs)+        forM_ (bins1 ++ bins2) $ \f -> do+          logDebug $ "rm " <> T.pack f+          rmFile f+    pure ()+++rmCache :: ( MonadReader env m+           , HasDirs env+           , HasLog env+           , MonadIO m+           , MonadMask m+           )+        => m ()+rmCache = do+  Dirs {..} <- getDirs+  contents <- liftIO $ listDirectory (fromGHCupPath cacheDir)+  forM_ contents $ \f -> do+    let p = fromGHCupPath cacheDir </> f+    logDebug $ "rm " <> T.pack p+    rmFile p+++rmTmp :: ( MonadReader env m+         , HasDirs env+         , HasLog env+         , MonadIO m+         , MonadMask m+         )+      => m ()+rmTmp = do+  ghcup_dirs <- liftIO getGHCupTmpDirs+  forM_ ghcup_dirs $ \f -> do+    logDebug $ "rm -rf " <> T.pack (fromGHCupPath f)+    rmPathForcibly f+
+ lib/GHCup/Command/HealthCheck.hs view
@@ -0,0 +1,176 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE MultiWayIf #-}++module GHCup.Command.HealthCheck where++import GHCup.Errors+import GHCup.Legacy.Utils+import GHCup.Prelude+import GHCup.Query.DB+import GHCup.Query.GHCupDirs+import GHCup.Types+import GHCup.Types.Optics++import Control.Exception+    (SomeException )+import Control.Exception.Safe         ( try, handleIO )+import Control.Monad                  ( forM )+import Control.Monad.IO.Class         ( liftIO )+import Control.Monad.Reader           ( MonadReader )+import Data.Functor                   ( (<&>) )+import Data.List                      ( foldl', sort )+import Data.Variant.Excepts+    ( pattern V, pattern VLeft, pattern VRight, runE )+import System.Directory               ( doesFileExist )+import System.FilePath                ( pathSeparator, (</>) )+import Text.PrettyPrint.HughesPJClass (Pretty(..), text, nest, vcat, ($$), ($+$))+import Witherable                     ( catMaybes, forMaybe )+++data SymlinkState = Fine FilePath FilePath+                  | DestinationDoesn'tExist FilePath FilePath+                  | WrongDestination FilePath FilePath FilePath+                  | AllWrong FilePath FilePath FilePath+                  | Missing FilePath+  deriving (Show, Ord, Eq)++instance Pretty SymlinkState where+  pPrint (DestinationDoesn'tExist f dest) = vcat $ fmap text+    [ "- Target does not exist:"+    , "  * Symlink: " <> f+    , "  * Target: "  <> dest+    ]+  pPrint (WrongDestination f should actual) = vcat $ fmap text+    [ "- Wrong target:"+    , "  * Symlink: " <> f+    , "  * Target (should): "  <> should+    , "  * Target (actual): "  <> actual+    ]+  pPrint (AllWrong f should actual) = vcat $ fmap text+    [ "- Wrong and broken target:"+    , "  * Symlink: " <> f+    , "  * Target (should): "  <> should+    , "  * Target (actual and broken): "  <> actual+    ]+  pPrint (Missing f) = vcat $ fmap text+    [ "- Symlink missing:"+    , "  * Symlink: " <> f+    ]+  pPrint (Fine f link) = vcat $ fmap text+    [ "- All good:"+    , "  * Symlink: " <> f+    , "  * Target: "  <> link+    ]++data ToolHealthCheck = ToolHealthCheck {+    thHaveInstFile   :: (FilePath, Bool)+  , thHaveSpecFile   :: (FilePath, Bool)+  , thParseSpecFile  :: Bool+  , thInstallDest    :: FilePath+  , thSupposedInstalledFiles :: Maybe Int+  , thMissingFiles   :: Maybe [FilePath]+  , thStrayFiles     :: Maybe [FilePath]+  , thSymlinkState   :: Maybe [SymlinkState]+  , thSetState       :: Maybe [SymlinkState]+  }+  deriving (Show)++instance Pretty ToolHealthCheck where+  pPrint ToolHealthCheck{..} = vcat+    [ let (f, e) = thHaveInstFile in text $ "Installed artifacts file exists at " <> f <> ": " <> show e+    , let (f, e) = thHaveSpecFile in text $ "Installed specification file exists at " <> f <> ": " <> show e+    , text $ "Can parse specification file: " <> show thParseSpecFile+    , text $ "Install destination: " <> show thInstallDest+    , text $ "Number of files that should be installed: " <> maybe "(no information)" show thSupposedInstalledFiles+    , text "Missing files:" $$ nest 4 (ppFiles thMissingFiles)+    , text "Stray files:" $$ nest 4 (ppFiles thStrayFiles)+    , text "Symlink status:" $$ nest 4 (ppFiles thSymlinkState)+    , text "Set symlink status:" $$ nest 4 (ppFiles thSetState)+    ]+   where+    ppFiles Nothing   = text "(no information)"+    ppFiles (Just []) = text "none"+    ppFiles (Just fs) = foldl' ($+$) mempty (map pPrint $ sort fs)++-- TODO+--   -     (_:_:_) -> lift $ do+--            logWarn $ "Looks like you have a corrupted DB/installation\n"+--                    <> "More than one revision installed of: " <> T.pack (prettyShow tool)+--   - detect legacy installations+dbHealthCheck ::+  ( MonadReader env m+  , HasDirs env+  , HasPlatformReq env+  , HasLog env+  , MonadIOish m+  )+  => Tool+  -> TargetVersion+  -> m ToolHealthCheck+dbHealthCheck tool tver = do+  Dirs{..} <- getDirs++  instFile <- recordedInstallationFile tool tver+  thHaveInstFile <- fmap (instFile,) $ liftIO $ doesFileExist instFile+  toolDest <- toolInstallDestination tool tver+  let thInstallDest = fromGHCupPath toolDest+  specFile <- recordedInstallationSpecFile tool tver++  (thHaveSpecFile, thParseSpecFile) <- fmap (\(a, b) -> ((specFile, a), b)) $ runE (getInstallMetadata tool tver) >>= \case+    VRight _ -> pure (True, True)+    VLeft (V (FileDoesNotExistError{})) -> pure (False, False)+    VLeft (V (ParseError{})) -> pure (True, False)+    VLeft _ -> fail "oops"++  symLSpec <- runE (getSymlinkSpec tool tver)++  thSymlinkState <- case symLSpec of+    VRight spec -> fmap Just $ do+      forMaybe spec $ \(SymlinkSpec target link _ _) -> do+        inspectSymlink (binDir </> link) target binDir toolDest+    VLeft _ -> pure Nothing++  installedFiles <- getInstalledFiles tool tver++  allFiles <- fmap (dropPrefix (fromGHCupPath toolDest <> [pathSeparator])) <$> liftIO (handleIO (\_ -> pure []) $ getFilesDeep toolDest)+  let thStrayFiles :: Maybe [FilePath] = installedFiles <&> \thif -> catMaybes $ allFiles <&> \f -> if f `notElem` thif then Just f else Nothing++  thMissingFiles <- forM installedFiles $ \mf -> forMaybe mf $ \f -> do+    b <- liftIO $ doesFileExist (fromGHCupPath toolDest </> f)+    if b then pure Nothing else pure (Just f)++  let thSupposedInstalledFiles = length <$> installedFiles++  thSetState <- runE (isSet tool tver) >>= \case+    VRight (Just _)+      | VRight spec <- symLSpec+      -> fmap Just $ forMaybe spec $ \case+           (SymlinkSpec _ _ _ Nothing) -> pure Nothing+           (SymlinkSpec target _ _ (Just setName)) -> inspectSymlink (binDir </> setName) target binDir toolDest+    VRight (Just _)+      | VLeft _ <- symLSpec+      -> pure Nothing+    VRight Nothing -> pure Nothing+    VLeft _ -> pure Nothing++  pure ToolHealthCheck{..}+ where+  inspectSymlink f target bindir tooldest = do+    mtfp <- try @_ @SomeException $ liftIO $ getLinkTarget f+    case mtfp of+      Left _ -> pure $ Just $ Missing f+      Right tfp -> do+        dest <- binarySymLinkDestination bindir (fromGHCupPath tooldest </> target)+        broken <- liftIO $ isBrokenSymlink f+        pure $ Just $ if | broken+                         , tfp /= dest+                         -> AllWrong f dest tfp+                         | broken+                         -> DestinationDoesn'tExist f tfp+                         | tfp /= dest+                         -> WrongDestination f dest tfp+                         | otherwise+                         -> Fine f dest+
+ lib/GHCup/Command/Install.hs view
@@ -0,0 +1,300 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}++module GHCup.Command.Install where++import GHCup.Builder+import GHCup.Command.Install.LowLevel+import GHCup.Command.Rm+import GHCup.Download+import GHCup.Errors+import GHCup.Input.SymlinkSpec+import GHCup.Prelude+import GHCup.Query.DB+import GHCup.Query.GHCupDirs+import GHCup.Query.Metadata+import GHCup.System.Cmd+import GHCup.Types+import GHCup.Types.Optics+import GHCup.Unpack++import Control.Applicative+import Control.Monad+#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Conduit                        ( runConduitRes, (.|) )+import Control.Monad.Reader+import Control.Monad.Trans.Resource   hiding ( throwM )+import Data.Maybe+import Data.Variant.Excepts+import Optics+import Prelude                        hiding ( abs )+import System.FilePath                ( dropDrive )+import System.IO.Error                ( doesNotExistErrorType )+import Text.PrettyPrint.HughesPJClass ( prettyShow )++import qualified Data.Conduit.Combinators as C+import qualified Data.Text                as T++++    -------------------------+    --[ Tool installation ]--+    -------------------------++-- | Installs cabal into @~\/.ghcup\/bin/cabal-\<ver\>@ and+-- creates a default @cabal -> cabal-x.y.z.q@ symlink for+-- the latest installed version.+installTool ::+  ( MonadReader env m+  , HasPlatformReq env+  , HasGHCupInfo env  -- this is the main difference to the other functions+  , HasDirs env+  , HasSettings env+  , HasLog env+  , MonadResource m+  , MonadIOish m+  )+  => Tool+  -> TargetVersionReq+  -> InstallDir+  -> Bool+  -> [String]+  -> Maybe [String]+  -> Excepts+       '[ AlreadyInstalled+        , CopyError+        , DigestError+        , ContentLengthError+        , GPGError+        , DownloadFailed+        , NoDownload+        , NotInstalled+        , UnknownArchive+        , TarDirDoesNotExist+        , ArchiveResult+        , FileAlreadyExistsError+        , URIParseError+        , NoInstallInfo+        , MergeFileTreeError+        , ProcessError+        , ParseError+        , DirNotEmpty+        , UninstallFailed+        , MalformedInstallInfo+        ]+       m+       (InstallationSpecResolved, FilePath)+installTool tool treq installDir forceInstall extraArgs installTargets = do+  GHCupInfo { _ghcupDownloads = dls } <- getGHCupInfo+  (rev, dlinfo) <- liftE $ getDownloadInfoE' tool treq+  installBindist+    tool+    (preview (_GHCupDownloads % ix tool % toolDetails % _Just) dls)+    dlinfo+    (TargetVersionRev (treq ^. tvqTargetVer) rev)+    installDir+    forceInstall+    extraArgs+    installTargets++-- | Like 'installTool', except takes the 'DownloadInfo' as+-- argument instead of looking it up from 'GHCupDownloads'.+installBindist ::+  ( MonadReader env m+  , HasPlatformReq env+  , HasDirs env+  , HasSettings env+  , HasLog env+  , MonadResource m+  , MonadIOish m+  )+  => Tool+  -> Maybe ToolDescription+  -> DownloadInfo+  -> TargetVersionRev+  -> InstallDir+  -> Bool           -- ^ Force install+  -> [String]+  -> Maybe [String]+  -> Excepts+       '[ AlreadyInstalled+        , CopyError+        , DigestError+        , ContentLengthError+        , GPGError+        , DownloadFailed+        , NoDownload+        , NotInstalled+        , UnknownArchive+        , TarDirDoesNotExist+        , ArchiveResult+        , FileAlreadyExistsError+        , URIParseError+        , NoInstallInfo+        , MergeFileTreeError+        , ProcessError+        , ParseError+        , DirNotEmpty+        , UninstallFailed+        , MalformedInstallInfo+        ]+       m+       (InstallationSpecResolved, FilePath)+installBindist tool toolDesc dlinfo trev@(TargetVersionRev tver rev) installDir forceInstall extraArgs installTargets = do+  lift $ logDebug $ "Requested to install "+                     <> T.pack (prettyShow tool)+                     <> " version " <> T.pack (prettyShow tver)++  installed <- lift $ isInstalled tool tver+  if+    | not forceInstall+    , Just irev <- installed+    , GHCupInternal <- installDir -> do+        if rev == irev+        then throwE $ AlreadyInstalled tool tver+        else do+          lift $ logInfo "Removing the currently installed revision first!"+          liftE $ rmToolVersion tool tver++    | forceInstall+    , Just _ <- installed+    , GHCupInternal <- installDir -> do+        lift $ logInfo "Removing the currently installed version first!"+        liftE $ rmToolVersion tool tver++    | otherwise -> pure ()+++  -- download (or use cached version)+  dl <- liftE $ downloadCached dlinfo Nothing++  case installDir of+    IsolateDir isoDir -> do             -- isolated install+      lift $ logInfo $ "isolated installing Cabal to " <> T.pack isoDir+      installSpec <- liftE $ installPackedBindist tool toolDesc dl dlinfo (IsolateDirResolved isoDir) trev forceInstall extraArgs installTargets+      pure (installSpec, isoDir)++    GHCupInternal -> do                 -- regular install+      instDir <- lift $ toolInstallDestination tool tver+      installSpec <- liftE $ installPackedBindist tool toolDesc dl dlinfo (GHCupDir instDir) trev forceInstall extraArgs installTargets+      pure (installSpec, fromGHCupPath instDir)++installPackedBindist ::+  ( MonadReader env m+  , HasDirs env+  , HasPlatformReq env+  , HasSettings env+  , HasLog env+  , MonadResource m+  , MonadIOish m+  )+  => Tool+  -> Maybe ToolDescription+  -> FilePath             -- ^ Path to the tarball+  -> DownloadInfo+  -> InstallDirResolved   -- ^ Path to install to+  -> TargetVersionRev+  -> Bool+  -> [String]+  -> Maybe [String]+  -> Excepts '[ CopyError+              , FileAlreadyExistsError+              , MergeFileTreeError+              , ProcessError+              , ParseError+              , UnknownArchive+              , TarDirDoesNotExist+              , DirNotEmpty+              , ArchiveResult+              , NoInstallInfo+              , MalformedInstallInfo+              ] m InstallationSpecResolved+installPackedBindist tool toolDesc dl dlInfo inst trev forceInstall extraArgs installTargets = do+  PlatformRequest {..} <- lift getPlatformReq++  unless forceInstall+    (liftE $ installDestSanityCheck inst)++  tmpUnpack <- lift withGHCupTmpDir+  liftE $ cleanUpOnError tmpUnpack (unpackToDir (fromGHCupPath tmpUnpack) dl)+  liftE $ catchWarn $ lEM @_ @'[ProcessError] $ darwinNotarization _rPlatform+    (fromGHCupPath tmpUnpack)++  -- the subdir of the archive where we do the work+  workdir <- fromGHCupPath <$> maybe (pure tmpUnpack)+    (liftE . intoSubdir tmpUnpack) (view dlSubdir dlInfo)++  tmpInstallDest <- lift withGHCupTmpDir++  liftE $ runBuildAction tmpUnpack $ installUnpackedBindist tool toolDesc workdir+        inst tmpInstallDest dlInfo trev forceInstall extraArgs installTargets++-- | Install an unpacked distribution.+installUnpackedBindist :: forall m env .+  ( HasLog env+  , HasDirs env+  , HasSettings env+  , HasPlatformReq env+  , MonadReader env m+  , MonadIOish m+  )+  => Tool+  -> Maybe ToolDescription+  -> FilePath             -- ^ Path to the unpacked cabal bindist (where the executable resides)+  -> InstallDirResolved   -- ^ Path to install to+  -> GHCupPath            -- ^ DESTDIR+  -> DownloadInfo+  -> TargetVersionRev+  -> Bool+  -> [String]+  -> Maybe [String]+  -> Excepts '[ CopyError+              , FileAlreadyExistsError+              , MergeFileTreeError+              , ProcessError+              , ParseError+              , NoInstallInfo+              , MalformedInstallInfo+              ] m InstallationSpecResolved+installUnpackedBindist tool toolDesc workdir installDest tmpInstallDest dlInfo trev@(TargetVersionRev tver _rev) forceInstall extraArgs installTargets = do+  instSpec <- liftE $ installationSpecFromMetadata' dlInfo tool tver+  lift $ logInfo $ "Installing " <> T.pack (prettyShow tool)+  liftE $ installTheSpec instSpec workdir installDest tmpInstallDest extraArgs installTargets forceInstall+  let preserveMtimes = _isPreserveMtimes instSpec+  resolvedSymlinkSpecs <- liftE $ forM (view isExeSymLinked instSpec) (resolveSymlinkSpec (tmpInstallDest `appendGHCupPath` dropDrive (fromInstallDir installDest)))+  let resolvedInstSpec = resolveInstallationSpec (mconcat resolvedSymlinkSpecs) instSpec++  -- then merge to the live filesystem+  liftE $ mergeToFileSystem tool tver installDest tmpInstallDest preserveMtimes forceInstall False++  -- TODO: move to optparse install+  -- symlinking+  Dirs {..} <- lift getDirs+  parsedSymlinkSpec <- forM (_isExeSymLinked resolvedInstSpec) (liftE . parseSymlinkSpec (_tvVersion tver))+  liftE $ symlinkBinaries installDest parsedSymlinkSpec (GHCupBinDir binDir) tool tver++  -- write InstallationInfo to the disk+  lift $ recordInstallationInfo installDest tool toolDesc trev dlInfo resolvedInstSpec+  pure resolvedInstSpec+++-- | Does basic checks for isolated installs+-- Isolated Directory:+--   1. if it doesn't exist -> proceed+--   2. if it exists and is empty -> proceed+--   3. if it exists and is non-empty -> panic and leave the house+installDestSanityCheck :: ( MonadIOish m+                          ) =>+                          InstallDirResolved ->+                          Excepts '[DirNotEmpty] m ()+installDestSanityCheck (IsolateDirResolved isoDir) = do+  hideErrorDef [doesNotExistErrorType] () $ do+    empty' <- lift $ runConduitRes $ getDirectoryContentsRecursiveUnsafe isoDir .| C.null+    when (not empty') (throwE $ DirNotEmpty isoDir)+installDestSanityCheck _ = pure ()
+ lib/GHCup/Command/Install/LowLevel.hs view
@@ -0,0 +1,281 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}++module GHCup.Command.Install.LowLevel where++import GHCup.Errors+import GHCup.Input.SymlinkSpec+import GHCup.Prelude+import GHCup.Prelude.Process+import GHCup.Query.DB+import GHCup.Query.GHCupDirs+import GHCup.Query.Symlink+import GHCup.System.Cmd+import GHCup.System.Directory+import GHCup.Types+import GHCup.Types.Optics++import Control.Applicative+import Control.Exception.Safe+import Control.Monad+import Data.Yaml.Pretty+#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Monad.Reader+import Data.Maybe+import Data.Variant.Excepts+import Data.Versions                hiding ( patch )+import Data.Void+import Prelude                      hiding ( abs )+import System.FilePath+import System.FilePattern.Directory++import qualified Data.ByteString       as B+import qualified Data.Text             as T+import qualified System.FilePath.Posix as Posix+import qualified Text.Megaparsec       as MP++++++mergeToFileSystem ::+  ( MonadMask m+  , MonadReader env m+  , HasDirs env+  , HasLog env+  , MonadCatch m+  , MonadIOish m+  )+  => Tool+  -> TargetVersion+  -> InstallDirResolved   -- ^ Path to install to+  -> GHCupPath            -- ^ DESTDIR+  -> Bool+  -> Bool+  -> Bool+  -> Excepts '[MergeFileTreeError] m ()+mergeToFileSystem tool tver installDest tmpInstallDest preserveMtimes forceInstall append = do+  mergeFileTree+    (tmpInstallDest `appendGHCupPath` dropDrive (fromInstallDir installDest))+    installDest+    tool+    tver+    (\f t -> if preserveMtimes+             then liftIO $ copyFuncMtime f t+             else liftIO $ install f t (not forceInstall)+++    )+    append+ where+  copyFuncMtime f t = do+    mtime <- ifM (pathIsSymbolicLink f) (pure Nothing) (Just <$> getModificationTime f)+    install f t (not forceInstall)+    forM_ mtime $ setModificationTime t++installTheSpec ::+  ( HasLog env+  , HasDirs env+  , HasSettings env+  , MonadReader env m+  , MonadIOish m+  )+  => InstallationSpecInput+  -> FilePath             -- ^ Path to the unpacked bindist+  -> InstallDirResolved   -- ^ Path to install to+  -> GHCupPath            -- ^ DESTDIR+  -> [String]+  -> Maybe [String]+  -> Bool+  -> Excepts '[ CopyError+              , MergeFileTreeError+              , ProcessError+              , ParseError+              , MalformedInstallInfo+              ] m ()+installTheSpec InstallationSpec{..} workdir installDest tmpInstallDest extraArgs installTargets forceInstall = do+  -- run configure first+  case _isConfigure of+    Just ConfigSpec{..} -> do+      addConfArgs <- lift $ sanitizefConfOptions extraArgs++      let configFile = fromMaybe "configure" _csConfigFile+      processedConfArgs <- forM _csConfigArgs $ \a -> either (throwE . ParseError . show) pure . parseDomain $ a+      newEnv <- forM _csConfigEnv $ \EnvSpec{..} -> liftIO (augmentEnvironment _esEnv _esUnion)+      liftE $ execWithWrapper "sh"+                       (("." Posix.</> configFile) : processedConfArgs <> addConfArgs+                       )+                       (Just workdir)+                       "ghc-configure"+                       newEnv+    _ -> pure ()++  -- then make+  case _isMake of+    Just MakeSpec{..} -> do+      processedMakeArgs <- either (throwE . ParseError . show) pure $ forM (fromMaybe _msMakeArgs installTargets) parseDomain+      newEnv <- forM _msMakeEnv $ \EnvSpec{..} -> liftIO (augmentEnvironment _esEnv _esUnion)+      liftE $ makeWithWrapper processedMakeArgs (Just workdir) "make" newEnv+    _ -> pure ()++  -- then copy files manually, if any+  forM_ _isExeRules $ \case+    InstallFileRule{..} -> do+      f <- copy _ibrInstallSource _ibrInstallDest+      lift $ chmod_755 f+    InstallFilePatternRule{..} -> do+      files <- liftIO $ getDirectoryFiles workdir _ibrInstallPattern+      forM_ files $ \file -> do+        f <- copy file Nothing+        lift $ chmod_755 f++  forM_ _isDataRules $ \case+    InstallFileRule{..} ->+      void $ copy _ibrInstallSource _ibrInstallDest+    InstallFilePatternRule{..} -> do+      files <- liftIO $ getDirectoryFiles workdir _ibrInstallPattern+      forM_ files $ \file -> copy file Nothing++ where+  copy source destFile = do+    let from = workdir </> source+        destDir = fromGHCupPath tmpInstallDest </> dropDrive (fromInstallDir installDest)+        into = destDir </> fromMaybe source destFile+    liftIO $ createDirRecursive' (takeDirectory into)+    copyFileE from into (not forceInstall)+    logDebug $ "cp " <> (if forceInstall then "-f " else "") <> T.pack from <> " " <> T.pack into+    pure into++  parseDomain = MP.parse domainParser ""++  domainParser :: MP.Parsec Void String String+  domainParser = concat <$> many anyOrKnownVars+   where+    -- TODO: make this more efficient+    anyOrKnownVars :: MP.Parsec Void String String+    anyOrKnownVars = MP.try (fmap (const (fromInstallDir installDest)) (MP.chunk "${PREFIX}"))+                 <|> MP.try (fmap (const (fromGHCupPath tmpInstallDest)) (MP.chunk "${TMPDIR}"))+                 <|> fmap (:[]) MP.anySingle++makeWithWrapper ::+  ( MonadIOish m+  , HasSettings env+  , HasLog env+  , HasDirs env+  , MonadReader env m+  )+  => [String]+  -> Maybe FilePath+  -> FilePath+  -> Maybe [(String, String)]+  -> Excepts+       '[ ProcessError+        ]+       m+       ()+makeWithWrapper args' mWorkDir logLabel mEnv = do+  mymake <- liftIO getBestMake+  liftE $ execWithWrapper mymake args' mWorkDir logLabel mEnv++execWithWrapper ::+  ( MonadIOish m+  , HasSettings env+  , HasLog env+  , HasDirs env+  , MonadReader env m+  )+  => String+  -> [String]+  -> Maybe FilePath+  -> FilePath+  -> Maybe [(String, String)]+  -> Excepts+       '[ ProcessError+        ]+       m+       ()+execWithWrapper cmd' args' mWorkDir logLabel mEnv = do+  Settings{ buildWrapper } <- lift getSettings+  case buildWrapper of+    Just ProcessSpec{..} ->+      lEM $ execLogged cmd (cmdArgs <> ["--"] <> (cmd':args')) mWorkDir logLabel mEnv+    Nothing ->+      lEM $ execLogged cmd' args' mWorkDir logLabel mEnv++-- | Write InstallationInfo to the disk.+recordInstallationInfo ::+  ( MonadReader env m+  , HasDirs env+  , HasLog env+  , MonadIOish m+  )+  => InstallDirResolved+  -> Tool+  -> Maybe ToolDescription+  -> TargetVersionRev+  -> DownloadInfo+  -> InstallationSpecResolved+  -> m ()+recordInstallationInfo installDest tool toolDesc TargetVersionRev{..} dlInfo instSpec+  | isSafeDir installDest = do+      spec <- recordedInstallationSpecFile tool _tvrTargetVer+      liftIO $ createDirectoryIfMissing True (takeDirectory spec)+      let metadata = InstallMetadata dlInfo instSpec toolDesc _tvrRev+      logDebug2 $ "Writing install metadata to " <> T.pack spec <> "\n  " <> T.pack (show metadata)+      liftIO $ encodeFilePretty spec metadata+  | otherwise = do+      logDebug2 $ "Skipping spec installation, because installing into isolated dir: " <> T.pack (show installDest)+      pure ()+ where+  encodeFilePretty file json =+    let encoded = encodePretty defConfig json+    in B.writeFile file encoded++sanitizefConfOptions :: MonadFail m => [String] -> m [String]+sanitizefConfOptions args+  | "--prefix" `elem` fmap (takeWhile (/= '=')) args = fail "Don't explicitly set --prefix ...aborting"+  | otherwise = pure args+++-- TODO: move to other module+-- | Symlink e.g. @~/.ghcup/ghc/9.6.7/bin/ghc@ to+-- @~/.ghcup/bin/ghc-9.6.7@.+--+-- But we follow the spec from the metadata.+symlinkBinaries ::+  ( HasLog env+  , MonadReader env m+  , HasDirs env   -- createLink needs it on windows+  , MonadIOish m+  )+  => InstallDirResolved                    -- ^ base dir of the tool+  -> [SymlinkSpec [Either Char Version]]   -- ^ symlink spec+  -> InstallDirResolved                    -- ^ binary dir+  -> Tool+  -> TargetVersion+  -> Excepts '[MalformedInstallInfo] m ()+symlinkBinaries (IsolateDirResolved _) _ _ _ _ = pure ()+symlinkBinaries (fromInstallDir -> toolDir) rawSpec bindir tool tver = do+  let spec = substituteSpec <$> rawSpec+  pvpSyms <- lift $ getPVPSymlinks' (fromInstallDir bindir) spec toolDir+  forM_ pvpSyms $ lift . uncurry createLink+  case bindir of+    IsolateDirResolved d -> linkMajor d+    GHCupDir d           -> linkMajor (fromGHCupPath d)+    GHCupBinDir d        -> whenM (lift isLatest) $ linkMajor d+ where+  linkMajor d = do+    let ver = _tvVersion tver+    pvpMajorSyms <- liftE $ getPVPMajorSymlinks' d rawSpec ver toolDir+    forM_ pvpMajorSyms $ lift . uncurry createLink+  isLatest = do+    vers <- getInstalledVersions tool (_tvTarget tver)+    let latestVer = _vrVersion $ maximum vers+    pure $ latestVer == _tvVersion tver+
+ lib/GHCup/Command/List.hs view
@@ -0,0 +1,368 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE UndecidableInstances #-}++{-|+Module      : GHCup.Command.List+Description : Listing versions and tools+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Command.List where++import GHCup.Errors+import GHCup.Query.DB+import GHCup.Query.DB.HLS   ( getHLSGHCs )+import GHCup.Query.Metadata+import GHCup.Types+import GHCup.Types.JSON+    ()+import GHCup.Types.Optics++import Control.Applicative+import Control.DeepSeq              ( NFData )+import Control.Monad+#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Monad.Reader+import Control.Monad.ST+import Data.Bifunctor+import Data.List+import Data.Maybe+import Data.STRef+import Data.Set             ( Set )+import Data.Text            ( Text )+import Data.Time.Calendar   ( Day )+import Data.Traversable.WithIndex ( iforM )+import Data.Variant.Excepts+import Data.Versions        hiding ( patch )+import Optics+import Prelude              hiding ( abs, writeFile )++import qualified Data.Map.Strict as M+import qualified Data.Map.Strict as Map+import qualified GHC.Generics    as GHC+++++++    ------------------+    --[ List tools ]--+    ------------------+++-- | Filter data type for 'listVersions'.+data ListCriteria+  = ListInstalled Bool+  | ListSet Bool+  | ListAvailable Bool+  deriving (Eq, Show)+++type ToolListResult = M.Map Tool (Maybe ToolDescription, [ListResult])+type ProcessedListResult = M.Map Tool (Maybe ToolDescription, M.Map (Maybe Text) (M.Map Version (M.Map Int ListResult)))++data RevTag = RevUpdate+            | RevOutdated+            | RevNormal+  deriving (Eq, Ord, Show, GHC.Generic)++instance NFData RevTag++-- | A list result describes a single tool version+-- and various of its properties.+data ListResult = ListResult+  { lVer :: Version+  , lCross :: Maybe Text+    -- ^ currently only for GHC+  , lRev :: (Int, RevTag)  -- the Bool indicates whether this is an update from an older rev+  , lTag :: [Tag]+  , lInstalled :: Bool+  , lSet :: Bool+    -- ^ currently active version+  , lStray :: Bool+    -- ^ not in download info+  , lNoBindist :: Bool+    -- ^ whether the version is available for this platform/arch+  , hlsPowered :: Bool+  , lReleaseDay :: Maybe Day+  }+  deriving (Eq, Ord, Show, GHC.Generic)++instance NFData ListResult++makeLensesWith (lensRules & lensField .~ mappingNamer (\n -> [n <> "L"])) ''ListResult++-- | Extract all available tool versions and their tags.+availableToolVersions :: GHCupDownloads -> Tool -> Map.Map TargetVersion VersionMetadata+availableToolVersions av tool = view+  (_GHCupDownloads % at tool % to ((unToolVersionSpec . _toolVersions) <$>) % non Map.empty)+  av+++-- | List all versions from the download info, as well as stray+-- versions.+listVersions ::+  forall m env .+  ( HasLog env+  , MonadReader env m+  , HasDirs env+  , HasPlatformReq env+  , HasGHCupInfo env+  , MonadIOish m+  )+  => Maybe [Tool]+  -> [ListCriteria]+  -> ShowRevisions+  -> Bool+  -> Bool+  -> (Maybe Day, Maybe Day)+  -> Excepts '[ParseError] m ToolListResult+listVersions lt' criteria showRevisions hideOld showNightly days = do+  GHCupInfo { _ghcupDownloads = dls } <- getGHCupInfo+  pfreq <- lift getPlatformReq+  instTools <- getAllInstalledTools lt'+  hlsGHCs <- let hlsSet = do+                   hlsMap <- instTools M.!? hls+                   (_, mSet) <- hlsMap M.!? Nothing+                   mSet+             in case hlsSet of+               Just VersionRev{..} -> do+                 getHLSGHCs _vrVersion+               Nothing -> pure []+  pure $ listVersions' dls pfreq instTools hlsGHCs lt' criteria showRevisions hideOld showNightly days++listVersions' ::+     GHCupDownloads+  -> PlatformRequest+  -> Map.Map Tool (Map.Map (Maybe Text) ([VersionRev], Maybe VersionRev))+  -> [Version]+  -> Maybe [Tool]+  -> [ListCriteria]+  -> ShowRevisions+  -> Bool+  -> Bool+  -> (Maybe Day, Maybe Day)+  -> ToolListResult+listVersions' dls pfreq instTools hlsGHCs lt' criteria showRevisions hideOld showNightly days =+  -- available tools from the metadata+  let allAvailableTools' :: [(Tool, [(TargetVersion, VersionMetadata)])]+        = maybe (allAvailableTools dls) (\ts -> filter (\(t, _) -> t `elem` ts) $ allAvailableTools dls) lt'+      avTools :: M.Map Tool (M.Map (Maybe Text) (Set (Version, VersionMetadata)))+        = M.fromList $ (fmap . fmap) groupByTargetS allAvailableTools'++      avToolsProcessed = runST $ do+        stRefAvToolsProcessed <- newSTRef mempty++        -- process installed tools first+        void $ iforM instTools $ \tool targetMap -> do+          iforM targetMap $ \target (vers', mset) ->+            forM_ vers' $ \vr@VersionRev{..} -> do+              let tver = TargetVersion target _vrVersion+                  mvm = getVersionMetadata tver tool dls+                  tags = maybe [] _vmTags mvm+                  lReleaseDay = mvm >>= _vmReleaseDay+                  lRev = (_vrRev, RevNormal)+                  tDesc = preview (_GHCupDownloads % ix tool % toolDetails % _Just) dls++                  hlsPowered = getHlsPowered tool target _vrVersion++              -- lNoBindist and lStray are updated when we traverse the metadata+              -- bindist tags (as opposed to tool tags) will also be added later+              let lr = ListResult { lVer = _vrVersion+                                  , lCross = target+                                  , lTag = tags+                                  , lSet = mset == Just vr+                                  , lInstalled = True+                                  , lNoBindist = False+                                  , lStray = True+                                  , ..+                                  }++              insertListResult stRefAvToolsProcessed tool target tDesc _vrVersion _vrRev lr++        installedProcessed <- readSTRef stRefAvToolsProcessed++        -- then process tools in the metadata, that are not installed+        -- and add the installed ones in the process+        void $ iforM avTools $ \tool targetMap -> do+          let tDesc = preview (ix tool % _1 % _Just) installedProcessed <|> preview (_GHCupDownloads % ix tool % toolDetails % _Just) dls+          iforM targetMap $ \target vers' ->+            forM_ vers' $ \(ver', VersionMetadata{..}) -> do+              -- versions from the metadata that's already installed+              let avInstVers :: M.Map Version (M.Map Int ListResult) =+                    fromMaybe mempty $ do+                      (_, m) <- installedProcessed M.!? tool+                      m M.!? target++              let lReleaseDay = _vmReleaseDay++              let (Rev latestMetaRev) = maximum $ M.keys (unRevisionSpec _vmRevisionSpec)+++              -- add all revision+              forM_ (M.toList (unRevisionSpec _vmRevisionSpec)) $ \(Rev metaRev, vi) -> do+                let mdli = getDownloadInfo' pfreq vi+                let bTags = fromMaybe [] $ mdli >>= _dlTag++                -- this has to consider the installed rev as well,+                -- which may or may not be in the metadata++                case iheadOf (ix ver' % itraversed) avInstVers of+                  -- it's installed+                  Just (installedRev, installedLr) -> do+                    if installedRev == metaRev+                    then do -- and even the same revision+                      -- add information from the metadata to the installed rev+                      modifyListResult stRefAvToolsProcessed tool target ver' installedRev+                        [ lNoBindistL .~ (isNothing mdli && not (lStray installedLr))+                        , lTagL       %~ (<> bTags)+                        , lStrayL     .~ False+                        ]+                    else do -- installed, but not this revision+                      when (showRevisions /= ShowNone) $ do++                        -- is it the latest revision?+                        let isLatestRev = metaRev == latestMetaRev && (metaRev > installedRev)+                        -- it could be an update+                        let isUpdate = isLatestRev++                        -- tag shenanigans+                        let dropOld = if isUpdate then filter (/= Old) else id+                            filterNotLatestRec = filter (`notElem` [Latest, Recommended])+                            dropLatestRec = if isLatestRev then id else filterNotLatestRec++                        when isUpdate $+                          -- remove the latest/recommended tag from the installed revision+                          modifyListResult stRefAvToolsProcessed tool target ver' installedRev+                            [ lRevL % _2 .~ RevOutdated+                            , lTagL      %~ filterNotLatestRec+                            ]++                        -- Insert the installed revision+                        -- updates are always inserted, but non-updates are only relevant if the user wants to see all revisions+                        let lrNew = ListResult+                                      { lVer = ver'+                                      , lCross = target+                                      , lTag = dropLatestRec $ dropOld (_vmTags <> bTags)+                                      , lSet = False+                                      , lInstalled = False+                                      , hlsPowered = False+                                      , lNoBindist = isNothing mdli+                                      , lStray = False+                                      , lRev = (metaRev, if isUpdate then RevUpdate else RevNormal)+                                      , ..+                                      }+                        when (showRevisions == ShowAll || isUpdate) $+                          insertListResult stRefAvToolsProcessed tool target tDesc ver' metaRev lrNew+                  -- not installed, just insert+                  Nothing -> do+                    let isLatestRev = metaRev == latestMetaRev+                    let lr = ListResult+                               { lVer = ver'+                               , lCross = target+                               , lTag = _vmTags <> bTags+                               , lSet = False+                               , lInstalled = False+                               , hlsPowered = False+                               , lNoBindist = isNothing mdli+                               , lStray = False+                               , lRev = (metaRev, RevNormal)+                               , ..+                               }+                    when (showRevisions == ShowAll || isLatestRev) $+                      insertListResult stRefAvToolsProcessed tool target tDesc ver' metaRev lr+        readSTRef stRefAvToolsProcessed++  in toToolListResult avToolsProcessed++ where+  toToolListResult :: ProcessedListResult -> ToolListResult+  toToolListResult = M.map (second (toListOf (traversed % traversed % traversed)))++  modifyListResult ::+       STRef s ProcessedListResult+    -> Tool+    -> Maybe Text+    -> Version+    -> Int+    -> [ListResult -> ListResult]+    -> ST s ()+  modifyListResult ref tool target ver' rev setters =+    modifySTRef' ref+      (ix tool % _2 % ix target % ix ver' % at rev %~ (>>= (\lr' -> filter' (foldl (&) lr' setters))))++  insertListResult ::+       STRef s ProcessedListResult+    -> Tool+    -> Maybe Text+    -> Maybe ToolDescription+    -> Version+    -> Int+    -> ListResult+    -> ST s ()+  insertListResult ref tool target tDesc ver' rev lr' =+    modifySTRef' ref+      (at tool % non (tDesc, mempty) % _2 % at target % non mempty % at ver' % non mempty % at rev .~ filter' lr')++  getHlsPowered tool target ver' =+    (tool == ghc && isNothing target) && ver' `elem` hlsGHCs++  filter' :: ListResult -> Maybe ListResult+  filter' lr = do+    lrN <- filterNightly lr+    lrOld <- filterOld lrN+    lrCrit <- if foldr (\a b -> fromCriteria a lrOld && b) True criteria+              then Just lrOld+              else Nothing+    filterDays lrCrit++  filterDays :: ListResult -> Maybe ListResult+  filterDays lr@ListResult{..} =+    case days of+      (Nothing, Nothing)    -> Just lr+      (Just from, Just to')+        | Just True <- (\d -> d >= from && d <= to') <$> lReleaseDay+        -> Just lr+        | otherwise -> Nothing+      (Nothing, Just to')+        | Just True <- (<= to') <$> lReleaseDay+        -> Just lr+        | otherwise -> Nothing+      (Just from, Nothing)+        | Just True <- (>= from) <$> lReleaseDay+        -> Just lr+        | otherwise -> Nothing++  fromCriteria :: ListCriteria -> ListResult -> Bool+  fromCriteria lc ListResult{..} = case lc of+    ListInstalled  b -> f b lInstalled+    ListSet        b -> f b lSet+    ListAvailable  b -> f b $ not lNoBindist+   where+    f b+      | b         = id+      | otherwise = not++  filterOld :: ListResult -> Maybe ListResult+  filterOld lr@ListResult {..}+    | hideOld   = if lInstalled || Old `notElem` lTag then Just lr else Nothing+    | otherwise = Just lr++  filterNightly :: ListResult -> Maybe ListResult+  filterNightly lr@ListResult {..}+    | showNightly = Just lr+    | otherwise   = if lInstalled || (Nightly `notElem` lTag && LatestNightly `notElem` lTag)+                    then Just lr+                    else Nothing+
+ lib/GHCup/Command/Nuke.hs view
@@ -0,0 +1,139 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}++{-|+Module      : GHCup.Command.Nuke+Description : GHCup nuke+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable++This module contains the main functions that correspond+to the command line interface, like installation, listing versions+and so on.++These are the entry points.+-}+module GHCup.Command.Nuke where+++import GHCup.Prelude+import GHCup.Query.GHCupDirs+import GHCup.Types+import GHCup.Types.Optics++import Conduit                ( sourceToList )+import Control.Applicative+import Control.Exception.Safe+import Control.Monad+#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Monad.Reader+import Control.Monad.Trans.Resource hiding ( throwM )+import Data.List+import Prelude                      hiding ( abs, writeFile )+import System.FilePath+import System.IO.Error++import qualified Data.Text as T++++++    ------------+    --[ Nuke ]--+    ------------+++rmGhcupDirs :: ( MonadReader env m+               , HasDirs env+               , MonadIO m+               , MonadUnliftIO m+               , HasLog env+               , MonadCatch m+               , MonadMask m )+            => m [FilePath]+rmGhcupDirs = do+  Dirs+    { baseDir+    , binDir+    , logsDir+    , cacheDir+    , recycleDir+    , dbDir+    , tmpDir+    } <- getDirs++  let envFilePath = fromGHCupPath baseDir </> "env"++  confFilePath <- getConfigFilePath++  handleRm $ rmEnvFile  envFilePath+  handleRm $ rmConfFile confFilePath++  -- for xdg dirs, the order matters here+  handleRm $ rmPathForcibly logsDir+  handleRm $ rmPathForcibly tmpDir+  handleRm $ rmPathForcibly cacheDir++  handleRm $ rmBinDir binDir+  handleRm $ rmPathForcibly recycleDir+  handleRm $ rmPathForcibly dbDir+  when isWindows $ do+    logInfo $ "removing " <> T.pack (fromGHCupPath baseDir </> "msys64")+    handleRm $ rmPathForcibly (baseDir `appendGHCupPath` "msys64")++  handleRm $ removeEmptyDirsRecursive (fromGHCupPath baseDir)++  -- report files in baseDir that are left-over after+  -- the standard location deletions above+  hideErrorDef [doesNotExistErrorType] [] $ reportRemainingFiles (fromGHCupPath baseDir)++  where+    handleRm :: (MonadReader env m, MonadCatch m, HasLog env, MonadIO m)  => m () -> m ()+    handleRm = handleIO (\e -> logDebug $ "Part of the cleanup action failed with error: " <> T.pack (displayException e) <> "\n"+                                <> "continuing regardless...")++    rmEnvFile :: (HasLog env, MonadReader env m, HasDirs env, MonadMask m, MonadIO m, MonadCatch m) => FilePath -> m ()+    rmEnvFile enFilePath = do+      logInfo "Removing Ghcup Environment File"+      hideErrorDef [permissionErrorType] () $ rmFileForce enFilePath++    rmConfFile :: (HasLog env, MonadReader env m, HasDirs env, MonadMask m, MonadIO m, MonadCatch m) => FilePath -> m ()+    rmConfFile confFilePath = do+      logInfo "removing Ghcup Config File"+      hideErrorDef [permissionErrorType] () $ rmFileForce confFilePath++    rmBinDir :: (MonadReader env m, HasDirs env, MonadMask m, MonadIO m, MonadCatch m) => FilePath -> m ()+    rmBinDir binDir+      | isWindows = removeDirIfEmptyOrIsSymlink binDir+      | otherwise = do+          isXDGStyle <- liftIO useXDG+          when (not isXDGStyle) $+            removeDirIfEmptyOrIsSymlink binDir++    reportRemainingFiles :: (MonadMask m, MonadIO m, MonadUnliftIO m) => FilePath -> m [FilePath]+    reportRemainingFiles dir = do+      remainingFiles <- runResourceT $ sourceToList $ getDirectoryContentsRecursiveUnsafe dir+      let normalizedFilePaths = fmap normalise remainingFiles+      let sortedByDepthRemainingFiles = sortBy (flip compareFn) normalizedFilePaths+      let remainingFilesAbsolute = fmap (dir </>) sortedByDepthRemainingFiles++      pure remainingFilesAbsolute++      where+        calcDepth :: FilePath -> Int+        calcDepth = length . filter isPathSeparator++        compareFn :: FilePath -> FilePath -> Ordering+        compareFn fp1 fp2 = compare (calcDepth fp1) (calcDepth fp2)++
+ lib/GHCup/Command/Prefetch.hs view
@@ -0,0 +1,119 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}++{-|+Module      : GHCup.Command.Prefetch+Description : GHCup installation functions+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Command.Prefetch where+++import GHCup.Download+import GHCup.Errors+import GHCup.Prelude+import GHCup.Query.Metadata+import GHCup.Types+import GHCup.Types.JSON+    ()+import GHCup.Types.Optics++import Control.Exception.Safe+import Control.Monad+#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Monad.Reader+import Control.Monad.Trans.Resource hiding ( throwM )+import Data.Maybe+import Data.Variant.Excepts+import Optics+import Prelude                      hiding ( abs, writeFile )++++    ---------------------+    --[ Tool fetching ]--+    ---------------------+++fetchToolBindist :: ( MonadFail m+                    , MonadMask m+                    , MonadCatch m+                    , MonadReader env m+                    , HasDirs env+                    , HasSettings env+                    , HasPlatformReq env+                    , HasGHCupInfo env+                    , HasLog env+                    , MonadResource m+                    , MonadIO m+                    , MonadUnliftIO m+                    )+                 => TargetVersionReq+                 -> Tool+                 -> Maybe FilePath+                 -> Excepts+                      '[ DigestError+                       , ContentLengthError+                       , GPGError+                       , DownloadFailed+                       , NoDownload+                       , URIParseError+                       ]+                      m+                      FilePath+fetchToolBindist v t mfp = do+  (_, dlinfo) <- liftE $ getDownloadInfoE' t v+  liftE $ downloadCached' dlinfo Nothing mfp+++fetchToolSrc :: ( MonadFail m+               , MonadMask m+               , MonadCatch m+               , MonadReader env m+               , HasDirs env+               , HasSettings env+               , HasPlatformReq env+               , HasGHCupInfo env+               , HasLog env+               , MonadResource m+               , MonadIO m+               , MonadUnliftIO m+               )+            => Tool+            -> TargetVersionReq+            -> Maybe FilePath+            -> Excepts+                 '[ DigestError+                  , ContentLengthError+                  , GPGError+                  , DownloadFailed+                  , NoDownload+                  , URIParseError+                  ]+                 m+                 FilePath+fetchToolSrc tool v@(TargetVersionReq{..}) mfp = do+  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo+  dlInfo <-+    preview (_GHCupDownloads+                % ix tool+                % toolVersionsL+                % ix _tvqTargetVer+                % revisionSpecL+                % ixOrLast _tvqRev+                % _2+                % viSourceDL+                % _Just+            ) dls+      ?? NoDownload v ghc Nothing+  liftE $ downloadCached' dlInfo Nothing mfp+
+ lib/GHCup/Command/Rm.hs view
@@ -0,0 +1,218 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}++module GHCup.Command.Rm where++import GHCup.Errors+import GHCup.Input.SymlinkSpec+import GHCup.Legacy.Cabal+import GHCup.Legacy.HLS+import GHCup.Legacy.Stack+import GHCup.Legacy.Utils+import GHCup.Prelude+import GHCup.Query.DB+import GHCup.Query.GHCupDirs+import GHCup.Query.Symlink+import GHCup.System.Directory+import GHCup.Types+import GHCup.Types.Optics++import Control.Applicative+import Control.Exception.Safe+import Control.Monad+#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Monad.Reader+import Control.Monad.Trans.Resource   hiding ( throwM )+import Data.List+import Data.Maybe+import Data.Variant.Excepts+import GHC.IO.Exception+import Prelude                        hiding ( abs, writeFile )+import System.Environment+import System.FilePath+import System.IO.Error+import System.IO.Temp++import qualified Data.Text as T+++-- | Remove a tool completely.+--+-- This has two phases:+--+-- 1. the files installed from the bindist+-- 2. the files symlinked into the GHCup bin directory+--+-- Both are stored on the DB, but in different files/formats.+rmToolVersion ::+  ( MonadReader env m+  , HasDirs env+  , HasLog env+  , HasPlatformReq env+  , MonadIOish m+  )+  => Tool+  -> TargetVersion+  -> Excepts '[NotInstalled, UninstallFailed, ParseError, MalformedInstallInfo] m ()+rmToolVersion tool tver = do+  logInfo $ "Removing " <> prettyText tool <> " version " <> prettyText tver+  let target = _tvTarget tver+      ver' = _tvVersion tver++  unlessM (lift $ fmap isJust $ isInstalled tool tver) $ throwE (NotInstalled tool tver)++  mset  <- liftE $ getSetVersion' tool target++  vspec <- lift $ runE $ getSymlinkSpec' tool tver++  case vspec of+    VLeft _ -> do+      -- legacy, no spec files+      pure ()+    VRight specRaw -> do+      let spec = substituteSpec <$> specRaw+      lift $ logInfo "Removing executable symlinks"++      toolDir <- fromGHCupPath <$> lift (toolInstallDestination tool tver)++      case mset of+        Just (vr@VersionRev{..}, mSetFile) -> do+          lift $ logDebug $ "Set version: " <> prettyVerRev vr+          when (_vrVersion == ver') $ lift $ do+              unqualSyml <- getUnqualifiedSymlinks spec toolDir+              forM_ unqualSyml (rmLink . snd)+              forM_ mSetFile recycleFile+              rmGHCShareDir+        Nothing -> pure ()++      pvpSyml <- lift $ getPVPSymlinks spec toolDir+      forM_ pvpSyml (lift . rmLink . snd)+      pvpMajorSyml <- liftE $ getPVPMajorSymlinks specRaw ver' toolDir+      forM_ pvpMajorSyml (rmLink . snd)+      f <- recordedInstallationSpecFile tool tver+      hideError NoSuchThing $ recycleFile f++  dir' <- lift $ toolInstallDestination tool tver+  let dir = fromGHCupPath dir'++  lift (getInstalledFiles tool tver) >>= \case+    Just files -> do+      -- @.spec@ file was added after the DB record files, so it's possible+      -- we may need to delete symlinks manually.+      -- We need to do this before the actual removal. The legacy methods+      -- rely on inspecting the internal GHC directories.+      case vspec of+        -- nothing to do, was already removed earlier+        VRight _ -> pure ()+        -- handle legacy symlink removal+        VLeft _+          | tool == ghc -> do+              liftE $ rmMinorGHCSymlinks tver+              liftE $ rmMajorGHCSymlinks tver+              set <- lift $ ghcSet target+              when (Just tver == set) $ do+                liftE $ rmPlainGHC target+                lift rmGHCShareDir++          | tool == hls -> do+              liftE $ rmMinorHLSSymlinks ver'+              set <- lift hlsSet+              when (Just ver' == set) $ liftE rmPlainHLS+          -- cabal and stack don't need special handling+          | otherwise -> pure ()++      lift $ logInfo $ "Removing files safely from: " <> T.pack dir+      forM_ files (lift . hideError NoSuchThing . recycleFile . (\f -> dir </> dropDrive f))+      hideError NoSuchThing $ hideError UnsatisfiedConstraints $ removeEmptyDirsRecursive dir+      survivors <- liftIO $ hideErrorDef [doesNotExistErrorType] [] $ listDirectory dir+      f <- recordedInstallationFile tool tver+      lift $ logDebug $ T.pack (show f)+      lift $ recycleFile f+      when (not (null survivors)) $ throwE $ UninstallFailed dir survivors++    Nothing+      | tool == ghc -> legacyGHCRm+      | tool == cabal -> liftE $ rmCabalVer ver'+      | tool == hls -> liftE $ rmHLSVer ver'+      | tool == stack -> liftE $ rmStackVer ver'+      | tool == ghcup -> lift rmGhcup+      | otherwise -> fail "Could not find installed files... your DB seems corrupted"+ where+  rmGHCShareDir = do+    Dirs {..}  <- getDirs+    hideError doesNotExistErrorType $ rmDirectoryLink (fromGHCupPath baseDir </> "share")+  legacyGHCRm = do+    liftE $ rmMinorGHCSymlinks tver+    liftE $ rmMajorGHCSymlinks tver+    set <- lift $ ghcSet (_tvTarget tver)+    when (Just tver == set) $ do+      liftE $ rmPlainGHC (_tvTarget tver)+      lift rmGHCShareDir+    ghcdir <- ghcupGHCDir tver+    let dir = fromGHCupPath ghcdir+    isDir <- liftIO $ doesDirectoryExist dir+    isSyml <- liftIO $ handleIO (\_ -> pure False) $ pathIsSymbolicLink dir+    when (isDir && not isSyml) $ do+      lift $ logInfo $ "Removing legacy directory recursively: " <> T.pack dir+      recyclePathForcibly ghcdir+++-- assuming the current scheme of having just 1 ghcup bin, no version info is required.+rmGhcup :: ( MonadReader env m+           , HasDirs env+           , MonadIO m+           , MonadCatch m+           , HasLog env+           , MonadMask m+           , MonadUnliftIO m+           )+        => m ()+rmGhcup = do+  Dirs { .. } <- getDirs+  let ghcupFilename = "ghcup" <> exeExt+  let ghcupFilepath = binDir </> ghcupFilename++  currentRunningExecPath <- liftIO getExecutablePath++  -- if paths do no exist, warn user, and continue to compare them, as is,+  -- which should eventually fail and result in a non-standard install warning++  p1 <- handleIO' doesNotExistErrorType+                  (handlePathNotPresent currentRunningExecPath)+                  (liftIO $ canonicalizePath currentRunningExecPath)++  p2 <- handleIO' doesNotExistErrorType+                  (handlePathNotPresent ghcupFilepath)+                  (liftIO $ canonicalizePath ghcupFilepath)++  let areEqualPaths = equalFilePath p1 p2++  unless areEqualPaths $ logWarn $ nonStandardInstallLocationMsg currentRunningExecPath++  if isWindows+  then do+    -- since it doesn't seem possible to delete a running exe on windows+    -- we move it to system temp dir, to be deleted at next reboot+    tmp <- liftIO $ getCanonicalTemporaryDirectory >>= \t -> createTempDirectory t "ghcup"+    hideError UnsupportedOperation $+              liftIO $ hideError NoSuchThing $+              moveFile ghcupFilepath (tmp </> "ghcup")+  else+    -- delete it.+    hideError doesNotExistErrorType $ rmFile ghcupFilepath++  where+    handlePathNotPresent fp _err = do+      logDebug $ "Error: The path does not exist, " <> T.pack fp+      pure fp++    nonStandardInstallLocationMsg path = T.pack $+      "current ghcup is invoked from a non-standard location: \n"+      <> path <>+      "\n you may have to uninstall it manually."
+ lib/GHCup/Command/Set.hs view
@@ -0,0 +1,191 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}++module GHCup.Command.Set where++import GHCup.Errors+import GHCup.Legacy.Cabal+import GHCup.Legacy.HLS+import GHCup.Legacy.Stack+import GHCup.Legacy.Utils (rmPlainGHC, binarySymLinkDestination, ghcInternalBinDir, ghcToolFiles)+import GHCup.Prelude+import GHCup.Query.DB+import GHCup.Query.GHCupDirs+import GHCup.Query.Symlink+import GHCup.System.Directory+import GHCup.Types+import GHCup.Types.Optics+import GHCup.Warnings++import Control.Applicative+import Control.Monad+#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Monad.Reader+import Data.Maybe+import Data.Data (Proxy(..))+import Data.Variant.Excepts+import Data.Versions        hiding ( patch )+import Prelude              hiding ( abs )+import System.FilePath+import System.IO.Error++import qualified Data.Text    as T+import qualified Data.Text.IO as T+import GHCup.Query.DB.HLS++setToolVersion ::+  ( MonadReader env m+  , HasDirs env+  , HasLog env+  , HasPlatformReq env+  , MonadIOish m+  )+  => Tool+  -> TargetVersion+  -> Excepts '[ParseError, NotInstalled] m TargetVersion+setToolVersion tool ver = setToolVersion' tool ver Nothing++setToolVersion' ::+  ( MonadReader env m+  , HasDirs env+  , HasLog env+  , HasPlatformReq env+  , MonadIOish m+  )+  => Tool+  -> TargetVersion+  -> Maybe FilePath        -- ^ if @Nothing@, then we operate in ~/.ghcup/bin,+                           --   otherwise in a tmp directory+  -> Excepts '[ParseError, NotInstalled] m TargetVersion+-- TODO: warn about hls compatibility+setToolVersion' tool tver mTmpDir = do+  hideExcept' @NoToolVersionSet Proxy $ when (isNothing mTmpDir) $ unsetTool tool (_tvTarget tver)++  let ver' = _tvVersion tver+  vspec <- lift $ runE $ getSymlinkSpec tool tver+  case vspec of+    -- legacy+    VLeft _+      | tool == ghc   -> liftE legacySetGHC+      | tool == cabal -> liftE $ setCabal ver' mTmpDir+      | tool == stack -> liftE $ setStack ver' mTmpDir+      | tool == hls   -> liftE $ setHLS ver' SetHLSOnly mTmpDir+      | otherwise -> throwE $ NotInstalled tool tver+    VRight spec -> do+      lift $ logDebug2 $ T.pack (show spec)+      toolDir <- lift $ fmap fromGHCupPath $ toolInstallDestination tool tver+      symls <- maybe+        (lift $ getUnqualifiedSymlinks spec toolDir)+        (\tmpDir -> lift $ getUnqualifiedSymlinks' tmpDir spec toolDir)+        mTmpDir+      shadows <- fmap catMaybes <$> forM symls $ \(target, bin) -> do+        lift $ createLink target bin+        liftIO (isShadowed bin) >>= \case+          Nothing -> pure Nothing+          Just pa -> pure $ Just (pa, bin)+      unless (null shadows) $ logWarn $ T.pack $ prettyHFError (ToolShadowed tool (_tvVersion tver) shadows)++  -- record in 'set' file+  when (isNothing mTmpDir) $ do+    setFile <- lift $ recordedSetVersionFile tool (_tvTarget tver)+    liftIO $ createDirRecursive' (takeDirectory setFile)+    liftIO $ T.writeFile setFile (prettyVer . _tvVersion $ tver)+    currentHLS <- liftE $ getSetVersion' hls Nothing+    currentGHC <- liftE $ getSetVersion' ghc Nothing+    supportedGHC <- lift $ maybe (pure []) (getHLSGHCs . _vrVersion . fst) currentHLS+    lift $ warnAboutHlsCompatibility (_vrVersion . fst <$> currentHLS) (_vrVersion . fst <$> currentGHC) supportedGHC++  pure tver+ where+  legacySetGHC = do+    binDir' <- maybe (binDir <$> lift getDirs) pure mTmpDir+    ghcdir <- lift $ ghcupGHCDir tver+    -- for ghc tools (ghc, ghci, haddock, ...)+    verfiles <- ghcToolFiles tver+    forM_ verfiles $ \file -> do+      -- create symlink+      internalBinDir <- ghcInternalBinDir tver+      let fullF = binDir' </> file  <> exeExt+      destL <- binarySymLinkDestination binDir' (internalBinDir </> file <> exeExt)+      lift $ createLink destL fullF++    when ((isNothing . _tvTarget $ tver) && isNothing mTmpDir)+      $ lift $ symlinkShareDir (fromGHCupPath ghcdir) (T.unpack $ prettyVer (_tvVersion tver))++  symlinkShareDir :: ( MonadReader env m+                     , HasDirs env+                     , HasLog env+                     , MonadIOish m+                     )+                  => FilePath+                  -> String+                  -> m ()+  symlinkShareDir ghcdir ver' = do+    Dirs {..} <- getDirs+    let destdir = fromGHCupPath baseDir+    let sharedir     = "share"+    let fullsharedir = ghcdir </> sharedir+    logDebug $ "Checking for sharedir existence: " <> T.pack fullsharedir+    whenM (liftIO $ doesDirectoryExist fullsharedir) $ do+      let fullF   = destdir </> sharedir+      let targetF = "." </> "ghc" </> ver' </> sharedir+      hideError doesNotExistErrorType $ rmDirectoryLink fullF++      if isWindows+      then liftIO+             -- On windows we need to be more permissive+             -- in case symlinks can't be created, be just+             -- give up here. This symlink isn't strictly necessary.+             $ hideError permissionErrorType+             $ hideError illegalOperationErrorType+             $ createDirectoryLink targetF fullF+      else liftIO+             $ createDirectoryLink targetF fullF++++unsetTool ::+  ( MonadReader env m+  , HasDirs env+  , HasLog env+  , HasPlatformReq env+  , MonadIOish m+  )+  => Tool+  -> Maybe T.Text+  -> Excepts '[ParseError, NotInstalled, NoToolVersionSet] m ()+unsetTool tool target = do+  unlessM (fmap isJust $ liftE $ getSetVersion' tool target) $ throwE (NoToolVersionSet tool target)++  mset <- liftE $ getSetVersion' tool target+  setFile <- lift $ recordedSetVersionFile tool target+  case mset of+    Just (VersionRev{..}, mSetFile) -> do+      let tver = TargetVersion target _vrVersion+      vspec <- lift $ runE $ getSymlinkSpec tool tver+      case vspec of+        VLeft _+          | tool == ghc -> liftE $ rmPlainGHC target+          | tool == cabal -> lift unsetCabal+          | tool == stack -> lift unsetStack+          | tool == hls -> lift unsetHLS+          | otherwise -> pure ()+        VRight spec -> do+          toolDir <- lift $ fmap fromGHCupPath $ toolInstallDestination tool tver+          unqualSyml <- lift $ getUnqualifiedSymlinks spec toolDir+          forM_ unqualSyml (rmLink . snd)+          forM_ mSetFile recycleFile+    Nothing -> pure ()+  when (tool == ghc) $ do+    Dirs {..} <- getDirs+    hideError doesNotExistErrorType $ rmDirectoryLink (fromGHCupPath baseDir </> "share")++  logDebug2 $ "rm -f " <> T.pack setFile+  hideError doesNotExistErrorType $ recycleFile setFile+
+ lib/GHCup/Command/Test/GHC.hs view
@@ -0,0 +1,199 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}++{-|+Module      : GHCup.Command.Test.GHC+Description : GHCup installation functions for GHC+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Command.Test.GHC where+++import GHCup.Builder+import GHCup.Command.Install.LowLevel+import GHCup.Download+import GHCup.Errors+import GHCup.Prelude+import GHCup.Query.GHCupDirs+import GHCup.Types+import GHCup.Types.Optics+import GHCup.Unpack++import Control.Applicative+import Control.Exception.Safe+import Control.Monad+#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Monad.Reader+import Control.Monad.Trans.Resource hiding ( throwM )+import Data.Maybe+import Data.Variant.Excepts+import Data.Versions                hiding ( patch )+import Optics+import Prelude                      hiding ( abs, writeFile )+import System.Environment+import System.FilePath+import URI.ByteString++import qualified Data.Map.Strict as Map+import qualified Data.Text       as T+++data GHCVer+  = SourceDist Version+  | GitDist GitBranch+  | RemoteDist URI+  deriving (Eq, Show)++++    --------------------+    --[ Tool testing ]--+    --------------------++++testGHCVer :: ( MonadFail m+              , MonadMask m+              , MonadCatch m+              , MonadReader env m+              , HasDirs env+              , HasSettings env+              , HasPlatformReq env+              , HasGHCupInfo env+              , HasLog env+              , MonadResource m+              , MonadIO m+              , MonadUnliftIO m+              )+           => TargetVersionReq+           -> [T.Text]+           -> Excepts+                '[ DigestError+                 , ContentLengthError+                 , GPGError+                 , DownloadFailed+                 , NoDownload+                 , ArchiveResult+                 , TarDirDoesNotExist+                 , UnknownArchive+                 , TestFailed+                 , URIParseError+                 ]+                m+                ()+testGHCVer tvr@TargetVersionReq{..} addMakeArgs = do+  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo++  dlInfo <-+    preview (_GHCupDownloads % ix ghc % toolVersionsL % ix _tvqTargetVer % revisionSpecL % ixOrLast _tvqRev % _2 % viTestDL % _Just) dls+      ?? NoDownload tvr ghc Nothing++  liftE $ testGHCBindist dlInfo _tvqTargetVer addMakeArgs++++testGHCBindist :: ( MonadFail m+                  , MonadMask m+                  , MonadCatch m+                  , MonadReader env m+                  , HasDirs env+                  , HasSettings env+                  , HasPlatformReq env+                  , HasGHCupInfo env+                  , HasLog env+                  , MonadResource m+                  , MonadIO m+                  , MonadUnliftIO m+                  )+               => DownloadInfo+               -> TargetVersion+               -> [T.Text]+               -> Excepts+                    '[ DigestError+                     , ContentLengthError+                     , GPGError+                     , DownloadFailed+                     , NoDownload+                     , ArchiveResult+                     , TarDirDoesNotExist+                     , UnknownArchive+                     , TestFailed+                     , URIParseError+                     ]+                    m+                    ()+testGHCBindist dlinfo ver addMakeArgs = do+  -- download (or use cached version)+  dl <- liftE $ downloadCached dlinfo Nothing++  liftE $ testPackedGHC dl (view dlSubdir dlinfo) ver addMakeArgs+++testPackedGHC :: ( MonadMask m+                 , MonadCatch m+                 , MonadReader env m+                 , HasDirs env+                 , HasPlatformReq env+                 , HasSettings env+                 , MonadThrow m+                 , HasLog env+                 , MonadIO m+                 , MonadUnliftIO m+                 , MonadFail m+                 , MonadResource m+                 )+              => FilePath          -- ^ Path to the packed GHC bindist+              -> Maybe TarDir      -- ^ Subdir of the archive+              -> TargetVersion  -- ^ The GHC version+              -> [T.Text]          -- ^ additional make args+              -> Excepts+                   '[ ArchiveResult, UnknownArchive, TarDirDoesNotExist, TestFailed ] m ()+testPackedGHC dl msubdir ver addMakeArgs = do+  -- unpack+  tmpUnpack <- lift mkGhcupTmpDir+  liftE $ cleanUpOnError tmpUnpack (unpackToDir (fromGHCupPath tmpUnpack) dl)++  -- the subdir of the archive where we do the work+  workdir <- maybe (pure tmpUnpack)+                   (liftE . intoSubdir tmpUnpack)+                   msubdir++  reThrowAll @_ @'[ArchiveResult, UnknownArchive, TarDirDoesNotExist, ProcessError]+    (TestFailed (fromGHCupPath workdir)) $ liftE $ runBuildAction tmpUnpack+                         (testUnpackedGHC workdir ver addMakeArgs)++testUnpackedGHC :: ( MonadReader env m+                   , HasDirs env+                   , HasSettings env+                   , HasLog env+                   , MonadIOish m+                   )+                => GHCupPath         -- ^ Path to the unpacked GHC bindist (where the make file resides)+                -> TargetVersion  -- ^ The GHC version+                -> [T.Text]          -- ^ additional configure args for bindist+                -> Excepts '[ProcessError] m ()+testUnpackedGHC path tver addMakeArgs = do+  lift $ logInfo $ "Testing GHC version " <> tVerToText tver <> "!"+  ghcDir <- lift $ ghcupGHCDir tver+  let ghcBinDir = fromGHCupPath ghcDir </> "bin"+  env <- liftIO $ addToPath [ghcBinDir] False+  let pathVar = if isWindows then "Path" else "PATH"+  forM_ (Map.lookup pathVar . Map.fromList $ env) $ liftIO . setEnv pathVar++  liftE $ makeWithWrapper (fmap T.unpack addMakeArgs)+              (Just $ fromGHCupPath path)+              "ghc-test"+              (Just $ ("STAGE1_GHC", maybe "" (T.unpack . (<> "-")) (_tvTarget tver)+                                     <> "ghc-"+                                     <> T.unpack (prettyVer $ _tvVersion tver)) : env)+  pure ()
+ lib/GHCup/Command/Upgrade.hs view
@@ -0,0 +1,160 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}++{-|+Module      : GHCup.Command.Upgrade+Description : GHCup upgrade+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Command.Upgrade where+++import GHCup.Download+import GHCup.Errors+import GHCup.Hardcoded.Version+import GHCup.Input.Parsers.URI+import GHCup.Prelude+import GHCup.Query.GHCupDirs+import GHCup.Query.Metadata+import GHCup.Types+import GHCup.Types.Optics++import Control.Applicative+import Control.Exception.Safe+import Control.Monad+#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Monad.Reader+import Control.Monad.Trans.Resource hiding ( throwM )+import Data.Maybe+import Data.Variant.Excepts+import Data.Versions                hiding ( patch )+import GHC.IO.Exception+import Prelude                      hiding ( abs, writeFile )+import System.FilePath++import qualified Data.Text as T++++++    -------------------------+    --[ GHCup upgrade etc ]--+    -------------------------++-- | Upgrade ghcup and place it in @~\/.ghcup\/bin\/ghcup@,+-- if no path is provided.+upgradeGHCup :: ( MonadMask m+                , MonadReader env m+                , HasDirs env+                , HasPlatformReq env+                , HasGHCupInfo env+                , HasSettings env+                , MonadCatch m+                , HasLog env+                , MonadThrow m+                , MonadFail m+                , MonadResource m+                , MonadIO m+                , MonadUnliftIO m+                )+             => Maybe FilePath    -- ^ full file destination to write ghcup into+             -> Bool              -- ^ whether to force update regardless+                                  --   of currently installed version+             -> Bool              -- ^ whether to throw an error if ghcup is shadowed+             -> Excepts+                  '[ CopyError+                   , DigestError+                   , ContentLengthError+                   , GPGError+                   , GPGError+                   , DownloadFailed+                   , NoDownload+                   , NoUpdate+                   , ToolShadowed+                   , URIParseError+                   ]+                  m+                  Version+upgradeGHCup mtarget force' fatal = do+  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo+  let latestVer = _tvVersion (fromJust (getLatest dls ghcup))+  upgradeGHCup' mtarget force' fatal latestVer+++-- | Upgrade ghcup and place it in @~\/.ghcup\/bin\/ghcup@,+-- if no path is provided.+upgradeGHCup' :: ( MonadMask m+                 , MonadReader env m+                 , HasDirs env+                 , HasPlatformReq env+                 , HasGHCupInfo env+                 , HasSettings env+                 , MonadCatch m+                 , HasLog env+                 , MonadThrow m+                 , MonadFail m+                 , MonadResource m+                 , MonadIO m+                 , MonadUnliftIO m+                 )+              => Maybe FilePath    -- ^ full file destination to write ghcup into+              -> Bool              -- ^ whether to force update regardless+                                   --   of currently installed version+              -> Bool              -- ^ whether to throw an error if ghcup is shadowed+              -> Version+              -> Excepts+                   '[ CopyError+                    , DigestError+                    , ContentLengthError+                    , GPGError+                    , GPGError+                    , DownloadFailed+                    , NoDownload+                    , NoUpdate+                    , ToolShadowed+                    , URIParseError+                    ]+                   m+                   Version+upgradeGHCup' mtarget force' fatal latestVer = do+  Dirs {..} <- lift getDirs+  lift $ logInfo "Upgrading GHCup..."+  (Just ghcupPVPVer) <- pure $ pvpToVersion ghcUpVer ""+  when (not force' && (latestVer <= ghcupPVPVer)) $ throwE NoUpdate+  (_, dli)   <- liftE $ getDownloadInfoE ghcup (VersionReq latestVer Nothing)+  tmp   <- fromGHCupPath <$> lift withGHCupTmpDir+  let fn = "ghcup" <> exeExt+  dlu <- lE $ parseURI' (_dlUri dli)+  p <- liftE $ download dlu Nothing (Just (_dlHash dli)) (_dlCSize dli) tmp (Just fn) False+  let destDir = takeDirectory destFile+      destFile = fromMaybe (binDir </> fn) mtarget+  lift $ logDebug $ "mkdir -p " <> T.pack destDir+  liftIO $ createDirRecursive' destDir+  lift $ logDebug $ "rm -f " <> T.pack destFile+  lift $ hideError NoSuchThing $ recycleFile destFile+  lift $ logDebug $ "cp " <> T.pack p <> " " <> T.pack destFile+  copyFileE p destFile False+  lift $ chmod_755 destFile++  liftIO (isInPath destFile) >>= \b -> unless b $+    lift $ logWarn $ T.pack (takeFileName destFile) <> " is not in PATH! You have to add it in order to use ghcup."+  liftIO (isShadowed destFile) >>= \case+    Nothing -> pure ()+    Just pa+      | fatal -> throwE (ToolShadowed ghcup latestVer [(pa, destFile)])+      | otherwise ->+        lift $ logWarn $ T.pack $ prettyHFError (ToolShadowed ghcup latestVer [(pa, destFile)])++  pure latestVer+
+ lib/GHCup/Command/Whereis.hs view
@@ -0,0 +1,107 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}++{-|+Module      : GHCup.Command.Whereis+Description : GHCup whereis+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Command.Whereis where+++import GHCup.Errors+import GHCup.Legacy.Utils+import GHCup.Prelude+import GHCup.Query.DB+import GHCup.Query.GHCupDirs+import GHCup.System.Directory+import GHCup.Types+import GHCup.Types.Optics++import Control.Applicative+import Control.Monad+#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Monad.Reader+import Data.Maybe+import Data.Variant.Excepts+import Data.Versions        hiding ( patch )+import Prelude              hiding ( abs, writeFile )+import System.Environment+import System.FilePath++import qualified Data.Text as T++++++    ---------------+    --[ Whereis ]--+    ---------------++++-- | Reports the binary location of a given tool:+--+--   * for GHC, this reports: @~\/.ghcup\/ghc\/\<ver\>\/bin\/ghc@+--   * for cabal, this reports @~\/.ghcup\/bin\/cabal-\<ver\>@+--   * for hls, this reports @~\/.ghcup\/bin\/haskell-language-server-wrapper-\<ver\>@+--   * for stack, this reports @~\/.ghcup\/bin\/stack-\<ver\>@+--   * for ghcup, this reports the location of the currently running executable+whereIsTool :: ( MonadReader env m+               , HasDirs env+               , HasLog env+               , HasPlatformReq env+               , MonadIOish m+               )+            => Tool+            -> TargetVersion+            -> Excepts '[NotInstalled, ParseError, NoInstallInfo] m FilePath+whereIsTool tool ver@TargetVersion {..} = do+  dirs <- lift getDirs+  sSpec <- lift $ getSymlinkSpecPortable tool ver+  toolDir <- fromGHCupPath <$> lift (toolInstallDestination tool ver)++  case sSpec of+    (SymlinkSpec{..}:_) ->+      pure $ toolDir </> _slTarget+    _ ->+      case tool of+        Tool "ghc" -> do+          whenM (lift $ fmap not $ ghcInstalled ver)+            $ throwE (NotInstalled ghc ver)+          bdir <- fromGHCupPath <$> lift (ghcupGHCDir ver)+          pure (bdir </> "bin" </> ghcBinaryName ver)+        Tool "cabal" -> do+          whenM (lift $ fmap not $ cabalInstalled _tvVersion)+            $ throwE (NotInstalled cabal (TargetVersion Nothing _tvVersion))+          pure (binDir dirs </> "cabal-" <> T.unpack (prettyVer _tvVersion) <> exeExt)+        Tool "hls" -> do+          whenM (lift $ fmap not $ hlsInstalled _tvVersion)+            $ throwE (NotInstalled hls (TargetVersion Nothing _tvVersion))+          ifM (lift $ isLegacyHLS _tvVersion)+            (pure (binDir dirs </> "haskell-language-server-wrapper-" <> T.unpack (prettyVer _tvVersion) <> exeExt))+            $ do+              bdir <- fromGHCupPath <$> lift (ghcupHLSDir _tvVersion)+              pure (bdir </> "bin" </> "haskell-language-server-wrapper" <> exeExt)++        Tool "stack" -> do+          whenM (lift $ fmap not $ stackInstalled _tvVersion)+            $ throwE (NotInstalled stack (TargetVersion Nothing _tvVersion))+          pure (binDir dirs </> "stack-" <> T.unpack (prettyVer _tvVersion) <> exeExt)+        Tool "ghcup" -> do+          currentRunningExecPath <- liftIO getExecutablePath+          liftIO $ canonicalizePath currentRunningExecPath+        -- TODO+        _ -> pure ""+
+ lib/GHCup/Compat/Pager.hs view
@@ -0,0 +1,69 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RankNTypes #-}++module GHCup.Compat.Pager where++import GHCup.Compat.Terminal+import GHCup.System.Directory++import Control.Exception  ( IOException, try )+import Control.Monad      ( forM_, (<=<) )+import Data.Foldable      ( asum )+import Data.Text          ( Text )+import System.Environment+import System.Exit+import System.IO+import System.Process++import qualified Data.Text    as T+import qualified Data.Text.IO as T+++getPager :: IO (Maybe FilePath)+getPager = do+  lookupEnv "GHCUP_PAGER" >>= \case+    Just r  -> pure $ Just r+    Nothing -> lookupEnv "PAGER" >>= \case+      Just r' -> pure $ Just r'+      Nothing ->+        let pagers = ["most", "more", "less"]+        in fmap (either (const Nothing) Just)+           . try @IOException+           . asum+           . fmap (maybe (fail "could not find") pure <=< findExecutable)+           $ pagers++-- 'more' reads from STDERR, and requires std_err to be 'Inherit'+sendToPager :: FilePath -> [Text] -> IO (Either IOException ())+sendToPager pager text = try @IOException+    $ withCreateProcess (shell pager) { std_in = CreatePipe+                                      , std_err = Inherit+                                      , std_out = Inherit+                                      , delegate_ctlc = True+                                      }+    $ \mStdinH _ _ ph -> case mStdinH of+          Just stdinH -> do+            forM_ text $ T.hPutStrLn stdinH+            hClose stdinH+            exitCode <- waitForProcess ph+            case exitCode of+              ExitFailure i -> fail ("Pager exited with exit code " <> show i)+              _             -> pure ()+          Nothing -> fail "well, I got nothing!"+++sendToPager' :: Maybe FilePath -> [Text] -> IO ()+sendToPager' (Just pager) text = do+  fits <- fitsInTerminal text+  case fits of+    Just True -> do+      T.putStr $ T.unlines text+    _ -> sendToPager pager text >>= \case+      Right _ -> pure ()+      Left _ -> do+        T.putStrLn $ T.unlines text+sendToPager' _ text =+  forM_ text T.putStrLn+
+ lib/GHCup/Compat/Terminal.hs view
@@ -0,0 +1,116 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RankNTypes #-}++module GHCup.Compat.Terminal where++import Control.Applicative+import Data.Char+import Data.Void++import qualified Data.Text                    as T+import qualified System.Console.Terminal.Size as TP+import qualified Text.Megaparsec              as MP+import qualified Text.Megaparsec.Char         as MPC+++-- | Checks whether the given text lines fit in the terminal window.+-- Returns 'Nothing' if the terminal size could not be determined (e.g. bc we're+-- part of a pipe).+fitsInTerminal :: [T.Text] -> IO (Maybe Bool)+fitsInTerminal text = fmap (\(TP.Window h _) -> length text <= h - 2) <$> TP.size++-- | Like 'fitsInTerminal', but takes a single text blob.+fitsInTerminal' :: T.Text -> IO (Maybe Bool)+fitsInTerminal' = fitsInTerminal . T.lines++padTo :: String -> Int -> String+padTo str x =+  let lstr = strWidth str+      add' = x - lstr+  in  if add' < 0 then str else str ++ replicate add' ' '+++-- | Calculate the render width of a string, considering+-- wide characters (counted as double width), ANSI escape codes+-- (not counted), and line breaks (in a multi-line string, the longest+-- line determines the width).+strWidth :: String -> Int+strWidth =+  maximum+    . (0 :)+    . map (foldr (\a b -> charWidth a + b) 0)+    . lines+    . stripAnsi++-- | Strip ANSI escape sequences from a string.+--+-- >>> stripAnsi "\ESC[31m-1\ESC[m"+-- "-1"+stripAnsi :: String -> String+stripAnsi s' =+  case+      MP.parseMaybe (many $ "" <$ MP.try ansi <|> pure <$> MP.anySingle) s'+    of+      Nothing -> error "Bad ansi escape"  -- PARTIAL: should not happen+      Just xs -> concat xs+ where+    -- This parses lots of invalid ANSI escape codes, but that should be fine+  ansi =+    MPC.string "\ESC[" *> digitSemicolons *> suffix MP.<?> "ansi" :: MP.Parsec+        Void+        String+        Char+  digitSemicolons = MP.takeWhileP Nothing (\c -> isDigit c || c == ';')+  suffix = MP.oneOf ['A', 'B', 'C', 'D', 'H', 'J', 'K', 'f', 'm', 's', 'u']++-- | Get the designated render width of a character: 0 for a combining+-- character, 1 for a regular character, 2 for a wide character.+-- (Wide characters are rendered as exactly double width in apps and+-- fonts that support it.) (From Pandoc.)+charWidth :: Char -> Int+charWidth c = case c of+  _ | c < '\x0300'                     -> 1+    | c >= '\x0300' && c <= '\x036F'   -> 0+    |  -- combining+      c >= '\x0370' && c <= '\x10FC'   -> 1+    | c >= '\x1100' && c <= '\x115F'   -> 2+    | c >= '\x1160' && c <= '\x11A2'   -> 1+    | c >= '\x11A3' && c <= '\x11A7'   -> 2+    | c >= '\x11A8' && c <= '\x11F9'   -> 1+    | c >= '\x11FA' && c <= '\x11FF'   -> 2+    | c >= '\x1200' && c <= '\x2328'   -> 1+    | c >= '\x2329' && c <= '\x232A'   -> 2+    | c >= '\x232B' && c <= '\x2E31'   -> 1+    | c >= '\x2E80' && c <= '\x303E'   -> 2+    | c == '\x303F'                    -> 1+    | c >= '\x3041' && c <= '\x3247'   -> 2+    | c >= '\x3248' && c <= '\x324F'   -> 1+    | -- ambiguous+      c >= '\x3250' && c <= '\x4DBF'   -> 2+    | c >= '\x4DC0' && c <= '\x4DFF'   -> 1+    | c >= '\x4E00' && c <= '\xA4C6'   -> 2+    | c >= '\xA4D0' && c <= '\xA95F'   -> 1+    | c >= '\xA960' && c <= '\xA97C'   -> 2+    | c >= '\xA980' && c <= '\xABF9'   -> 1+    | c >= '\xAC00' && c <= '\xD7FB'   -> 2+    | c >= '\xD800' && c <= '\xDFFF'   -> 1+    | c >= '\xE000' && c <= '\xF8FF'   -> 1+    | -- ambiguous+      c >= '\xF900' && c <= '\xFAFF'   -> 2+    | c >= '\xFB00' && c <= '\xFDFD'   -> 1+    | c >= '\xFE00' && c <= '\xFE0F'   -> 1+    | -- ambiguous+      c >= '\xFE10' && c <= '\xFE19'   -> 2+    | c >= '\xFE20' && c <= '\xFE26'   -> 1+    | c >= '\xFE30' && c <= '\xFE6B'   -> 2+    | c >= '\xFE70' && c <= '\xFEFF'   -> 1+    | c >= '\xFF01' && c <= '\xFF60'   -> 2+    | c >= '\xFF61' && c <= '\x16A38'  -> 1+    | c >= '\x1B000' && c <= '\x1B001' -> 2+    | c >= '\x1D000' && c <= '\x1F1FF' -> 1+    | c >= '\x1F200' && c <= '\x1F251' -> 2+    | c >= '\x1F300' && c <= '\x1F773' -> 1+    | c >= '\x20000' && c <= '\x3FFFD' -> 2+    | otherwise                        -> 1
lib/GHCup/Download.hs view
@@ -1,9 +1,9 @@-{-# LANGUAGE CPP                   #-}-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE TypeApplications      #-}-{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}  {-| Module      : GHCup.Download@@ -25,70 +25,78 @@ module GHCup.Download where  #if defined(INTERNAL_DOWNLOADER)-import           GHCup.Download.IOStreams-import           GHCup.Download.Utils+import GHCup.Download.IOStreams #endif-import           GHCup.Errors-import           GHCup.Types-import qualified GHCup.Types.Stack                as Stack-import           GHCup.Types.Optics-import           GHCup.Types.JSON               ( )-import           GHCup.Utils.Dirs-import           GHCup.Utils.URI-import           GHCup.Platform-import           GHCup.Prelude-import           GHCup.Prelude.File-import           GHCup.Prelude.Logger.Internal-import           GHCup.Prelude.Process-import           GHCup.Version+import GHCup.Errors+import GHCup.Types+import GHCup.Types.JSON+    ()+import GHCup.Types.Optics+#if defined(DHALL)+import GHCup.Types.Dhall+    ()+#endif+import GHCup.Hardcoded.URLs+import GHCup.Input.Parsers.URI+import GHCup.Prelude+import GHCup.Prelude.Process+import GHCup.Query.GHCupDirs+import GHCup.Query.System+import GHCup.System.Directory -import           Control.Applicative-import           Control.Exception.Safe-import           Control.Monad+import qualified GHCup.Types.Stack as Stack++import Control.Applicative+import Control.Exception.Safe+import Control.Monad #if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )+import Control.Monad.Fail ( MonadFail ) #endif-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-                                         hiding ( throwM )-import           Data.Aeson-import           Data.ByteString                ( ByteString )+import Control.Monad.Reader+import Control.Monad.Trans.Resource hiding ( throwM )+import Data.Aeson++#if defined(DHALL)+import qualified Data.ByteString.Lazy as BL+import           Data.Void            ( Void )+import qualified Dhall+import qualified Dhall.Binary         as Dhall+#endif++import Data.ByteString ( ByteString ) #if defined(INTERNAL_DOWNLOADER)-import           Data.CaseInsensitive           ( mk )+import Data.CaseInsensitive ( mk ) #endif-import           Data.Maybe-import           Data.Either-import           Data.List-import           Data.Time.Clock-import           Data.Time.Clock.POSIX-import           Data.Versions-import           Data.Word8              hiding ( isSpace )-import           Data.Variant.Excepts+import Data.Either+import Data.List+import Data.Maybe+import Data.Time.Clock+import Data.Time.Clock.POSIX+import Data.Variant.Excepts+import Data.Versions+import Data.Word8            hiding ( isSpace ) #if defined(INTERNAL_DOWNLOADER)-import           Network.Http.Client     hiding ( URL )+import Network.Http.Client hiding ( URL ) #endif-import           Optics-import           Prelude                 hiding ( abs-                                                , readFile-                                                , writeFile-                                                )-import           Safe-import           System.Environment-import           System.Exit-import           System.FilePath-import           System.IO.Error-import           System.IO.Temp-import           URI.ByteString          hiding (parseURI)+import Optics+import Prelude            hiding ( abs, readFile, writeFile )+import Safe+import System.Environment+import System.Exit+import System.FilePath+import System.IO.Error+import System.IO.Temp+import URI.ByteString     hiding ( parseURI ) -import qualified Crypto.Hash.SHA256            as SHA256-import qualified Data.ByteString               as B-import qualified Data.ByteString.Base16        as B16-import qualified Data.ByteString.Lazy          as L-import qualified Data.Map.Strict               as M-import qualified Data.Text                     as T-import qualified Data.Text.IO                  as T-import qualified Data.Text.Encoding            as E-import qualified Data.Yaml.Aeson               as Y+import qualified Crypto.Hash.SHA256     as SHA256+import qualified Data.ByteString        as B+import qualified Data.ByteString.Base16 as B16+import qualified Data.ByteString.Lazy   as L+import qualified Data.Map.Strict        as M+import qualified Data.Text              as T+import qualified Data.Text.Encoding     as E+import qualified Data.Text.IO           as T+import qualified Data.Yaml.Aeson        as Y   @@ -102,28 +110,45 @@     ------------------  +getDownloadsF ::+  ( FromJSONKey Tool+  , FromJSONKey Version+  , FromJSON VersionInfo+  , MonadReader env m+  , HasSettings env+  , HasDirs env+  , HasLog env+  , MonadIOish m+  )+  => PlatformRequest+  -> Excepts+       '[DigestError, ContentLengthError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError, StackPlatformDetectError, UnsupportedMetadataFormat]+                   m+                   GHCupInfo+getDownloadsF pfreq = do+  Settings { urlSource } <- lift getSettings+  getDownloadsF' pfreq urlSource  -- | Downloads the download information! But only if we need to ;P-getDownloadsF :: ( FromJSONKey Tool-                 , FromJSONKey Version-                 , FromJSON VersionInfo-                 , MonadReader env m-                 , HasSettings env-                 , HasDirs env-                 , MonadIO m-                 , MonadCatch m-                 , HasLog env-                 , MonadThrow m-                 , MonadFail m-                 , MonadMask m-                 )-              => PlatformRequest-              -> Excepts-                   '[DigestError, ContentLengthError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError, StackPlatformDetectError]+--+-- This ignores the 'urlSource' from 'Settings'.+getDownloadsF' ::+  ( FromJSONKey Tool+  , FromJSONKey Version+  , FromJSON VersionInfo+  , MonadReader env m+  , HasSettings env+  , HasDirs env+  , HasLog env+  , MonadIOish m+  )+  => PlatformRequest+  -> [NewURLSource]+  -> Excepts+       '[DigestError, ContentLengthError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError, StackPlatformDetectError, UnsupportedMetadataFormat]                    m                    GHCupInfo-getDownloadsF pfreq@(PlatformRequest arch plat _) = do-  Settings { urlSource } <- lift getSettings+getDownloadsF' pfreq@(PlatformRequest arch plat _) urlSource = do   infos <- liftE $ mapM dl' urlSource   keys <- if any isRight infos           then liftE . reThrowAll @_ @_ @'[StackPlatformDetectError] StackPlatformDetectError $ getStackPlatformKey pfreq@@ -149,7 +174,7 @@          )       => NewURLSource       -> Excepts-           '[DownloadFailed, GPGError, DigestError, ContentLengthError, JSONError, FileDoesNotExistError]+           '[DownloadFailed, GPGError, DigestError, ContentLengthError, JSONError, FileDoesNotExistError, UnsupportedMetadataFormat]            m (Either GHCupInfo Stack.SetupInfo)   dl' NewGHCupURL       = fmap Left $ liftE (getBase ghcupURL) >>= liftE . decodeMetadata @GHCupInfo   dl' NewStackSetupURL  = fmap Right $ liftE (getBase stackSetupURL) >>= liftE . decodeMetadata @Stack.SetupInfo@@ -159,10 +184,21 @@   dl' (NewSetupInfo si) = pure (Right si)   dl' (NewURI uri)      = do                             base <- liftE $ getBase uri-                            catchE @JSONError (\(JSONDecodeError s) -> do-                                logDebug $ "Couldn't decode " <> T.pack base <> " as GHCupInfo, trying as SetupInfo: " <> T.pack s-                                Right <$> decodeMetadata @Stack.SetupInfo base)-                              $ fmap Left (decodeMetadata @GHCupInfo base >>= \gI -> warnOnMetadataUpdate uri gI >> pure gI)+                            gr <- runE $ decodeMetadata @GHCupInfo base >>= \gI -> warnOnMetadataUpdate uri gI >> pure gI+                            case gr of+                              VRight r -> pure $ Left r+                              VLeft (V (JSONDecodeError ge)) -> do+                                logDebug $ "Couldn't decode " <> T.pack base <> " as GHCupInfo, trying as SetupInfo: " <> T.pack ge+                                sr <- runE $ decodeMetadata @Stack.SetupInfo base+                                case sr of+                                  VRight r -> pure $ Right r+                                  VLeft (V (JSONDecodeError se)) -> do+                                    throwE $ JSONDecodeError $ "\nError decoding as GHCupInfo:\n"+                                      <> (unlines . fmap ("  " <>) . lines $ ge)+                                      <> "\nError decoding as StackSetupURL:\n"+                                      <> (unlines . fmap ("  " <>) . lines $ se)+                                  VLeft err -> throwSomeE err+                              VLeft err -> throwSomeE err    fromStackSetupInfo :: MonadThrow m                      => Stack.SetupInfo@@ -171,19 +207,19 @@   fromStackSetupInfo (Stack.siGHCs -> ghcDli) keys = do     let ghcVersionsPerKey = (`M.lookup` ghcDli) . T.pack <$> keys         ghcVersions = fromMaybe mempty . listToMaybe . catMaybes $ ghcVersionsPerKey-    (ghcupInfo' :: M.Map GHCTargetVersion DownloadInfo) <--      M.mapKeys mkTVer <$> M.traverseMaybeWithKey (\_ a -> pure $ fromStackDownloadInfo a) ghcVersions-    let ghcupDownloads' = M.singleton GHC (M.map fromDownloadInfo ghcupInfo')+    (ghcupInfo' :: M.Map TargetVersion DownloadInfo) <-+      M.mapKeys mkTVer <$> M.traverseMaybeWithKey (\v a -> pure $ fromStackDownloadInfo v a) ghcVersions+    let ghcupDownloads' = GHCupDownloads $ M.singleton ghc (ToolInfo (ToolVersionSpec $ M.map fromDownloadInfo ghcupInfo') Nothing)     pure (GHCupInfo mempty ghcupDownloads' Nothing)    where-    fromDownloadInfo :: DownloadInfo -> VersionInfo-    fromDownloadInfo dli = let aspec = MapIgnoreUnknownKeys $ M.singleton arch (MapIgnoreUnknownKeys $ M.singleton plat (M.singleton Nothing dli))-                           in VersionInfo [] Nothing Nothing Nothing Nothing aspec Nothing Nothing Nothing Nothing+    fromDownloadInfo :: DownloadInfo -> VersionMetadata+    fromDownloadInfo dli = let aspec = ArchitectureSpec $ MapIgnoreUnknownKeys $ M.singleton arch (PlatformSpec $ MapIgnoreUnknownKeys $ M.singleton plat (PlatformVersionSpec $ M.singleton Nothing dli))+                           in VersionMetadata [] Nothing Nothing Nothing Nothing Nothing Nothing (RevisionSpec . M.singleton (Rev 0) . VersionInfo Nothing Nothing $ aspec) -    fromStackDownloadInfo :: MonadThrow m => Stack.GHCDownloadInfo -> m DownloadInfo-    fromStackDownloadInfo (Stack.GHCDownloadInfo { gdiDownloadInfo = Stack.DownloadInfo{..} }) = do+    fromStackDownloadInfo :: MonadThrow m => Version -> Stack.GHCDownloadInfo -> m DownloadInfo+    fromStackDownloadInfo ver (Stack.GHCDownloadInfo { gdiDownloadInfo = Stack.DownloadInfo{..} }) = do       sha256 <- maybe (throwM $ DigestMissing downloadInfoUrl) (pure . E.decodeUtf8) downloadInfoSha256-      pure $ DownloadInfo downloadInfoUrl (Just $ RegexDir "ghc-.*") sha256 Nothing Nothing Nothing+      pure $ DownloadInfo downloadInfoUrl (Just $ RegexDir "ghc-.*") sha256 Nothing Nothing Nothing (Just $ toInstallationInputSpec $ defaultGHCInstallSpec pfreq $ mkTVer ver)     mergeGhcupInfo :: MonadFail m@@ -191,9 +227,13 @@                  -> m GHCupInfo   mergeGhcupInfo [] = fail "mergeGhcupInfo: internal error: need at least one GHCupInfo"   mergeGhcupInfo xs@(GHCupInfo{}: _) =-    let newDownloads   = M.unionsWith (M.unionWith (\_ b2 -> b2)) (_ghcupDownloads   <$> xs)+    let newDownloads =+          M.unionsWith+            (\(ToolInfo (ToolVersionSpec a) td) (ToolInfo (ToolVersionSpec a') td') ->+              ToolInfo (ToolVersionSpec (M.unionWith (\_ b2 -> b2) a a')) (td <|> td'))+            (unGHCupDownloads . _ghcupDownloads <$> xs)         newToolReqs    = M.unionsWith (M.unionWith (\_ b2 -> b2)) (_toolRequirements <$> xs)-    in pure $ GHCupInfo newToolReqs newDownloads Nothing+    in pure $ GHCupInfo newToolReqs (GHCupDownloads newDownloads) Nothing   @@ -242,8 +282,8 @@   warnCache :: (MonadReader env m, HasLog env, MonadMask m, MonadCatch m, MonadIO m) => FilePath -> Downloader -> m ()   warnCache s downloader' = do     let tryDownloder = case downloader' of-                         Curl -> "Wget"-                         Wget -> "Curl"+                         Curl     -> "Wget"+                         Wget     -> "Curl" #if defined(INTERNAL_DOWNLOADER)                          Internal -> "Curl" #endif@@ -323,17 +363,17 @@   | scheme' uri == "file"   , urlBase' uri /= urlBase' newUri = do       confFile <- getConfigFilePath'-      logWarn $ "New metadata version detected"+      logWarn $ "New available metadata version detected"                            <> "\n    old URI: " <> (decUTF8Safe . serializeURIRef') uri                            <> "\n    new URI: " <> (decUTF8Safe . serializeURIRef') newUri-                           <> "\nYou might need to update your " <> T.pack confFile+                           <> "\nRun 'ghcup upgrade' first. If the waring persists, then you might need to update your " <> T.pack confFile   | scheme' uri /= "file"   , uri /= newUri = do       confFile <- getConfigFilePath'-      logWarn $ "New metadata version detected"+      logWarn $ "New available metadata version detected"                            <> "\n    old URI: " <> (decUTF8Safe . serializeURIRef') uri                            <> "\n    new URI: " <> (decUTF8Safe . serializeURIRef') newUri-                           <> "\nYou might need to update your " <> T.pack confFile+                           <> "\nRun 'ghcup upgrade' first. If the waring persists, then you might need to update your " <> T.pack confFile  where   scheme' = view (uriSchemeL' % schemeBSL')   urlBase' = T.unpack . decUTF8Safe . urlBaseName . view pathL'@@ -350,19 +390,55 @@                , HasLog env                , MonadMask m                , FromJSON j+#if defined(DHALL)+               , Dhall.FromDhall j+#endif                )                => FilePath-               -> Excepts '[JSONError, FileDoesNotExistError] m j-decodeMetadata actualYaml = do-  lift $ logDebug $ "Decoding yaml at: " <> T.pack actualYaml+               -> Excepts '[JSONError, FileDoesNotExistError, UnsupportedMetadataFormat] m j+decodeMetadata metadata+  | takeExtension metadata `elem` [".yaml", ".yml"]= do+      lift $ logDebug $ "Decoding yaml at: " <> T.pack metadata+      liftE $ yamlMeta metadata+  | takeExtension metadata == ".json" = do+      lift $ logDebug $ "Decoding json at: " <> T.pack metadata+      liftE $ jsonMeta metadata+#if defined(DHALL)+  | takeExtension metadata == ".dhall" = do+      lift $ logDebug $ "Decoding dhall at: " <> T.pack metadata+      liftE $ dhallMeta metadata+  | takeExtension metadata `elem` [".dhallb", ".dhall-binary"] = do+      lift $ logDebug $ "Decoding dhall binary at: " <> T.pack metadata+      liftE $ dhallbMeta metadata+#endif+  | otherwise = throwE $ UnsupportedMetadataFormat (takeExtension metadata) -  liftE-    . onE_ (onError actualYaml)-    . lEM' @_ @_ @'[JSONError] (\(displayException -> e) -> JSONDecodeError $ unlines [e, "Consider removing " <> actualYaml <> " manually."])-    . liftIO-    . Y.decodeFileEither-    $ actualYaml  where+#if defined(DHALL)+  dhallbMeta f =+      onE_ (onError f)+      . handleIO (\(displayException -> e) -> throwE @_ @'[JSONError] $ JSONDecodeError $ unlines [e, "Consider removing " <> f <> " manually."])+      . liftIO+      $ BL.readFile f >>= either (fail . show) pure . Dhall.decodeExpression @Void @Void >>= Dhall.rawInput Dhall.auto+  dhallMeta f =+      onE_ (onError f)+      . handleIO (\(displayException -> e) -> throwE @_ @'[JSONError] $ JSONDecodeError $ unlines [e, "Consider removing " <> f <> " manually."])+      . liftIO+      . Dhall.inputFile Dhall.auto+      $ f+#endif+  jsonMeta f =+      onE_ (onError f)+      . lEM' @_ @_ @'[JSONError] (\e -> JSONDecodeError $ unlines [e, "Consider removing " <> f <> " manually."])+      . liftIO+      . eitherDecodeFileStrict+      $ f+  yamlMeta f =+      onE_ (onError f)+      . lEM' @_ @_ @'[JSONError] (\(displayException -> e) -> JSONDecodeError $ unlines [e, "Consider removing " <> f <> " manually."])+      . liftIO+      . Y.decodeFileEither+      $ f   -- On error, remove the etags file and set access time to 0. This should ensure the next invocation   -- may re-download and succeed.   onError :: (MonadReader env m, HasLog env, MonadMask m, MonadCatch m, MonadIO m) => FilePath -> m ()@@ -373,62 +449,6 @@     liftIO $ hideError doesNotExistErrorType $ setAccessTime fp (posixSecondsToUTCTime (fromIntegral @Int 0))  -getDownloadInfo :: ( MonadReader env m-                   , HasPlatformReq env-                   , HasGHCupInfo env-                   )-                => Tool-                -> Version-                -- ^ tool version-                -> Excepts-                     '[NoDownload]-                     m-                     DownloadInfo-getDownloadInfo t v = getDownloadInfo' t (mkTVer v)--getDownloadInfo' :: ( MonadReader env m-                    , HasPlatformReq env-                    , HasGHCupInfo env-                    )-                 => Tool-                 -> GHCTargetVersion-                 -- ^ tool version-                 -> Excepts-                      '[NoDownload]-                      m-                      DownloadInfo-getDownloadInfo' t v = do-  pfreq@(PlatformRequest a p mv) <- lift getPlatformReq-  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo--  let distro_preview f g =-        let platformVersionSpec =-              preview (ix t % ix v % viArch % to unMapIgnoreUnknownKeys % ix a % to unMapIgnoreUnknownKeys % ix (f p)) dls-            mv' = g mv-        in  fmap snd-              .   find-                    (\(mverRange, _) -> maybe-                      (isNothing mv')-                      (\range -> maybe False (`versionRange` range) mv')-                      mverRange-                    )-              .   M.toList-              =<< platformVersionSpec-      with_distro        = distro_preview id id-      without_distro_ver = distro_preview id (const Nothing)-      without_distro     = distro_preview (set _Linux UnknownLinux) (const Nothing)--  maybe-    (throwE $ NoDownload v t (Just pfreq))-    pure-    (case p of-      -- non-musl won't work on alpine-      Linux Alpine -> with_distro <|> without_distro_ver-      _            -> with_distro <|> without_distro_ver <|> without_distro-    )--- -- | Tries to download from the given http or https url -- and saves the result in continuous memory into a file. -- If the filename is not provided, then we:@@ -481,9 +501,9 @@           (\e' -> do             lift $ hideError doesNotExistErrorType $ recycleFile (tmpFile baseDestFile)             case e' of-              V e@GPGError {} -> throwE e+              V e@GPGError {}    -> throwE e               V e@DigestError {} -> throwE e-              _ -> throwE (DownloadFailed e')+              _                  -> throwE (DownloadFailed e')           ) $ do               Settings{ downloader, noNetwork, gpgSetting } <- lift getSettings               when noNetwork $ throwE (DownloadFailed (V NoNetwork :: V '[NoNetwork]))@@ -744,12 +764,13 @@                -> Excepts '[URIParseError, DigestError, ContentLengthError, DownloadFailed, GPGError] m FilePath downloadCached dli mfn = do   Settings{ cache } <- lift getSettings-  case cache of-    True -> downloadCached' dli mfn Nothing-    False -> do-      dlu <- lE $ parseURI' (_dlUri dli)-      tmp <- lift withGHCupTmpDir-      liftE $ download dlu Nothing (Just (_dlHash dli)) (_dlCSize dli) (fromGHCupPath tmp) outputFileName False+  dlu <- lE $ parseURI' (_dlUri dli)+  let scheme = view (uriSchemeL' % schemeBSL') dlu+  if cache && scheme /= "file"+  then downloadCached' dli mfn Nothing+  else do+    tmp <- lift withGHCupTmpDir+    liftE $ download dlu Nothing (Just (_dlHash dli)) (_dlCSize dli) (fromGHCupPath tmp) outputFileName False  where   outputFileName = mfn <|> _dlOutput dli @@ -808,8 +829,7 @@   when verify $ do     let p' = takeFileName file     lift $ logInfo $ "verifying digest of: " <> T.pack p'-    c <- liftIO $ L.readFile file-    cDigest <- throwEither . E.decodeUtf8' . B16.encode . SHA256.hashlazy $ c+    cDigest <- liftIO $ getFileDigest file     when ((cDigest /= eDigest) && verify) $ throwE (DigestError file cDigest eDigest)  checkCSize :: ( MonadReader env m@@ -891,3 +911,9 @@     Just (DownloadMirror auth Nothing) ->       uri { uriAuthority = Just auth } applyMirrors _ uri = uri++getFileDigest :: FilePath -> IO T.Text+getFileDigest file = do+  c <- liftIO $ L.readFile file+  throwEither . E.decodeUtf8' . B16.encode . SHA256.hashlazy $ c+
lib/GHCup/Download/IOStreams.hs view
@@ -11,7 +11,7 @@ import           GHCup.Errors import           GHCup.Types.JSON               ( ) import           GHCup.Prelude-import           GHCup.Utils.URI+import           GHCup.Input.Parsers.URI  import           Control.Applicative import           Control.Exception.Safe@@ -171,8 +171,8 @@ withConnection' https host port = bracket acquire closeConnection   where-  acquire = case https of-    True -> do+  acquire = if https+    then do       ctx <- baselineContextSSL       openConnectionSSL ctx host (fromIntegral $ fromMaybe 443 port)-    False -> openConnection host (fromIntegral $ fromMaybe 80 port)+    else openConnection host (fromIntegral $ fromMaybe 80 port)
− lib/GHCup/Download/Utils.hs
@@ -1,60 +0,0 @@-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE TypeFamilies          #-}---module GHCup.Download.Utils where---import           GHCup.Errors-import           GHCup.Types.Optics-import           GHCup.Types.JSON               ( )-import           GHCup.Prelude--import           Control.Applicative-import           Control.Monad-import           Data.ByteString                ( ByteString )-import           Data.Maybe-import           Data.Variant.Excepts-import           Optics-import           Prelude                 hiding ( abs-                                                , readFile-                                                , writeFile-                                                )-import           URI.ByteString--import qualified Data.Binary.Builder           as B-import qualified Data.ByteString               as BS-import qualified Data.ByteString.Lazy          as L----- | Extracts from a URI type: (https?, host, path+query, port)-uriToQuadruple :: Monad m-               => URI-               -> Excepts-                    '[UnsupportedScheme]-                    m-                    (Bool, ByteString, ByteString, Maybe Int)-uriToQuadruple URI {..} = do-  let scheme = view schemeBSL' uriScheme--  host <--    preview (_Just % authorityHostL' % hostBSL') uriAuthority-      ?? UnsupportedScheme--  https <- if-    | scheme == "https" -> pure True-    | scheme == "http"  -> pure False-    | otherwise         -> throwE UnsupportedScheme--  let queryBS =-        BS.intercalate "&"-          . fmap (\(x, y) -> encodeQuery x <> "=" <> encodeQuery y)-          $ queryPairs uriQuery-      port =-        preview (_Just % authorityPortL' % _Just % portNumberL') uriAuthority-      fullpath = if BS.null queryBS then uriPath else uriPath <> "?" <> queryBS-  pure (https, host, fullpath, port)-  where encodeQuery = L.toStrict . B.toLazyByteString . urlEncodeQuery-
lib/GHCup/Errors.hs view
@@ -1,12 +1,12 @@ {-# OPTIONS_GHC -Wno-orphans #-}-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds               #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE RankNTypes #-} {-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TypeOperators           #-}-{-# LANGUAGE FlexibleInstances           #-}-{-# LANGUAGE RankNTypes           #-}+{-# LANGUAGE TypeOperators #-}  {-| Module      : GHCup.Errors@@ -19,23 +19,25 @@ -} module GHCup.Errors ( module GHCup.Errors, URIParseError ) where -import           GHCup.Types+import GHCup.Types -import           Control.Exception.Safe-import           Data.ByteString                ( ByteString )-import           Data.CaseInsensitive           ( CI )-import           Data.Text                      ( Text )-import           Data.Versions-import           Data.Variant-import           System.FilePath-import           Text.PrettyPrint               hiding ( (<>) )-import           Text.PrettyPrint.HughesPJClass hiding ( (<>) )-import           URI.ByteString+import Control.Exception.Safe+import Data.ByteString                ( ByteString )+import Data.CaseInsensitive           ( CI )+import Data.Data                      ( Proxy (..) )+import Data.Text                      ( Text )+import Data.Time                      ( Day )+import Data.Variant+import Data.Versions+import System.FilePath+import Text.PrettyPrint               hiding ( (<>) )+import Text.PrettyPrint.HughesPJClass hiding ( (<>) )+import URI.ByteString+import Data.Functor ((<&>)) -import qualified Data.Map.Strict               as M-import qualified Data.Text                     as T-import           Data.Data (Proxy(..))-import Data.Time (Day)+import qualified Data.Map.Strict as M+import qualified Data.Text       as T+import Data.List (intercalate)   @@ -85,6 +87,10 @@     , let proxy = Proxy :: Proxy ContentLengthError in format proxy     , let proxy = Proxy :: Proxy DuplicateReleaseChannel in format proxy     , let proxy = Proxy :: Proxy UnsupportedSetupCombo in format proxy+    , let proxy = Proxy :: Proxy UnsupportedMetadataFormat in format proxy+    , let proxy = Proxy :: Proxy NoInstallInfo in format proxy+    , let proxy = Proxy :: Proxy MalformedInstallInfo in format proxy+    , let proxy = Proxy :: Proxy IncompatibleConfig in format proxy     , ""     , "# high level errors (4000+)"     , let proxy = Proxy :: Proxy DownloadFailed in format proxy@@ -190,11 +196,39 @@     --[ Low-level errors ]--     ------------------------ +data NoInstallInfo = NoInstallInfo Tool TargetVersion+  deriving (Show) +instance Pretty NoInstallInfo where+  pPrint (NoInstallInfo tool tver) = text "Could not find install info for" <+> pPrint tool <+> text "version" <+> pPrint tver +instance HFErrorProject NoInstallInfo where+  eBase _ = 380+  eDesc _ = "Could not find install info for tool"++data IncompatibleConfig = IncompatibleConfig String+  deriving (Show)++instance Pretty IncompatibleConfig where+  pPrint (IncompatibleConfig str) = text ("Incompatible config: " <> str)++instance HFErrorProject IncompatibleConfig where+  eBase _ = 390+  eDesc _ = "Could not find install info for tool"++data MalformedInstallInfo = MalformedInstallInfo String+  deriving (Show)++instance Pretty MalformedInstallInfo where+  pPrint (MalformedInstallInfo str') = text $ "The installation info from the metadata did not pass validation: " <> str'++instance HFErrorProject MalformedInstallInfo where+  eBase _ = 400+  eDesc _ = "The installation info did not pass validation!"+ -- | A compatible platform could not be found. data NoCompatiblePlatform = NoCompatiblePlatform String -- the platform we got-  deriving Show+  deriving (Show)  instance Pretty NoCompatiblePlatform where   pPrint (NoCompatiblePlatform str') =@@ -205,14 +239,14 @@   eDesc _ = "No compatible platform could be found"  -- | Unable to find a download for the requested version/distro.-data NoDownload = NoDownload GHCTargetVersion Tool (Maybe PlatformRequest)-  deriving Show+data NoDownload = NoDownload TargetVersionReq Tool (Maybe PlatformRequest)+  deriving (Show)  instance Pretty NoDownload where-  pPrint (NoDownload tver@(GHCTargetVersion mtarget vv) tool mpfreq) =+  pPrint (NoDownload treq@(TargetVersionReq (TargetVersion mtarget vv) _) tool mpfreq) =     let helperMsg           | (Just target) <- mtarget-          , target `elem` (T.pack . prettyShow <$> enumFromTo (minBound :: Tool) (maxBound :: Tool)) =+          , T.unpack (T.toLower target) `elem` ["ghc", "cabal", "hls", "stack"] =               "\nPerhaps you meant: 'ghcup <command> "               <> T.unpack target               <> " "@@ -222,7 +256,7 @@     in text $ "Unable to find a download for "              <> show tool              <> " version "-             <> "'" <> T.unpack (tVerToText tver) <> "'"+             <> "'" <> prettyShow treq <> "'"              <> maybe "" (\pfreq -> " on detected platform " <> pfReqToString pfreq) mpfreq              <> helperMsg @@ -231,8 +265,9 @@   eDesc _ = "Unable to find a download for the requested version/distro."  -- | No update available or necessary.-data NoUpdate = NoUpdate-  deriving Show+data NoUpdate+  = NoUpdate+  deriving (Show)  instance Pretty NoUpdate where   pPrint NoUpdate = text (eDesc (Proxy :: Proxy NoUpdate))@@ -243,7 +278,7 @@  -- | The Architecture is unknown and unsupported. data NoCompatibleArch = NoCompatibleArch String-  deriving Show+  deriving (Show)  instance Pretty NoCompatibleArch where   pPrint (NoCompatibleArch arch) =@@ -254,8 +289,9 @@   eDesc _ = "The Architecture is unknown and unsupported"  -- | Unable to figure out the distribution of the host.-data DistroNotFound = DistroNotFound-  deriving Show+data DistroNotFound+  = DistroNotFound+  deriving (Show)  instance Pretty DistroNotFound where   pPrint DistroNotFound =@@ -267,7 +303,7 @@  -- | The archive format is unknown. We don't know how to extract it. data UnknownArchive = UnknownArchive FilePath-  deriving Show+  deriving (Show)  instance Pretty UnknownArchive where   pPrint (UnknownArchive file) =@@ -278,8 +314,9 @@   eDesc _ = "The archive format is unknown. We don't know how to extract it."  -- | The scheme is not supported (such as ftp).-data UnsupportedScheme = UnsupportedScheme-  deriving Show+data UnsupportedScheme+  = UnsupportedScheme+  deriving (Show)  instance Pretty UnsupportedScheme where   pPrint UnsupportedScheme =@@ -291,7 +328,7 @@  -- | Unable to copy a file. data CopyError = CopyError String-  deriving Show+  deriving (Show)  instance Pretty CopyError where   pPrint (CopyError reason) =@@ -302,13 +339,18 @@   eDesc _ = "Unable to copy a file."  -- | Unable to merge file trees.-data MergeFileTreeError = MergeFileTreeError IOException FilePath FilePath-  deriving Show+data MergeFileTreeError = MergeFileTreeErrorPreCondition IOException FilePath FilePath+                        | MergeFileTreeError IOException FilePath Tool TargetVersion+  deriving (Show)  instance Pretty MergeFileTreeError where-  pPrint (MergeFileTreeError e from to) =-    text "Failed to merge file tree from" <+> text from <+> text "to" <+> text to <+> text "\nexception was:" <+> text (displayException e)-     <+> text "\n...you may need to delete" <+> text to <+> text "manually. Make sure it's gone."+  pPrint (MergeFileTreeErrorPreCondition e from to) =+    text "Unmet precondition for merging file tree from" <+> text from <+> text "to" <+> text to <+> text "\nexception was:" <+> text (displayException e)+  pPrint (MergeFileTreeError e to tool tver) =+    text ("Error during merging file tree (" <> displayException e <> ")")+     <+> text "\nYou may need to delete" <+> text to <+> text "manually."+     <+> text "\nAlso run: ghcup healthcheck " <+> pPrint tool <+> pPrint tver+     <+> text "\nBecause ghcup database might now be corrupted."  instance HFErrorProject MergeFileTreeError where   eBase _ = 80@@ -316,7 +358,7 @@  -- | Unable to find a tag of a tool. data TagNotFound = TagNotFound Tag Tool-  deriving Show+  deriving (Show)  instance Pretty TagNotFound where   pPrint (TagNotFound tag tool) =@@ -328,7 +370,7 @@  -- | Unable to find a release day of a tool data DayNotFound = DayNotFound Day Tool (Maybe Day)-  deriving Show+  deriving (Show)  instance Pretty DayNotFound where   pPrint (DayNotFound day tool Nothing) =@@ -344,7 +386,7 @@ -- | Unable to find the next version of a tool (the one after the currently -- set one). data NextVerNotFound = NextVerNotFound Tool-  deriving Show+  deriving (Show)  instance Pretty NextVerNotFound where   pPrint (NextVerNotFound tool) =@@ -355,8 +397,8 @@   eDesc _ = "Unable to find the next version of a tool (the one after the currently set one)"  -- | The tool (such as GHC) is already installed with that version.-data AlreadyInstalled = AlreadyInstalled Tool Version-  deriving Show+data AlreadyInstalled = AlreadyInstalled Tool TargetVersion+  deriving (Show)  instance Pretty AlreadyInstalled where   pPrint (AlreadyInstalled tool ver') =@@ -368,8 +410,10 @@   eDesc _ = "The tool (such as GHC) is already installed with that version"  -- | The Directory is supposed to be empty, but wasn't.-data DirNotEmpty = DirNotEmpty {path :: FilePath}-  deriving Show+data DirNotEmpty = DirNotEmpty+  { path :: FilePath+  }+  deriving (Show)  instance Pretty DirNotEmpty where   pPrint (DirNotEmpty path) = do@@ -381,8 +425,8 @@  -- | The tool is not installed. Some operations rely on a tool -- to be installed (such as setting the current GHC version).-data NotInstalled = NotInstalled Tool GHCTargetVersion-  deriving Show+data NotInstalled = NotInstalled Tool TargetVersion+  deriving (Show)  instance Pretty NotInstalled where   pPrint (NotInstalled tool ver) =@@ -393,7 +437,7 @@   eDesc _ = "The required tool is not installed"  data UninstallFailed = UninstallFailed FilePath [FilePath]-  deriving Show+  deriving (Show)  instance Pretty UninstallFailed where   pPrint (UninstallFailed dir files) =@@ -405,7 +449,7 @@  -- | An executable was expected to be in PATH, but was not found. data NotFoundInPATH = NotFoundInPATH FilePath-  deriving Show+  deriving (Show)  instance Exception NotFoundInPATH @@ -419,7 +463,7 @@  -- | JSON decoding failed. data JSONError = JSONDecodeError String-  deriving Show+  deriving (Show)  instance Pretty JSONError where   pPrint (JSONDecodeError err) =@@ -432,8 +476,10 @@ -- | A file that is supposed to exist does not exist -- (e.g. when we use file scheme to "download" something). data FileDoesNotExistError = FileDoesNotExistError FilePath-  deriving Show+  deriving (Show) +instance Exception FileDoesNotExistError+ instance Pretty FileDoesNotExistError where   pPrint (FileDoesNotExistError file) =     text $ "File " <> file <> " does not exist."@@ -446,7 +492,7 @@ -- (e.g. when we use isolated installs with the same path). -- (e.g. This is done to prevent any overwriting) data FileAlreadyExistsError = FileAlreadyExistsError FilePath-  deriving Show+  deriving (Show)  instance Pretty FileAlreadyExistsError where   pPrint (FileAlreadyExistsError file) =@@ -457,11 +503,13 @@   eDesc _ = "A file already exists that wasn't expected to exist"  data TarDirDoesNotExist = TarDirDoesNotExist TarDir-  deriving Show+  deriving (Show)  instance Pretty TarDirDoesNotExist where-  pPrint (TarDirDoesNotExist dir) =+  pPrint (TarDirDoesNotExist (RealDir dir)) =     text "Tar directory does not exist:" <+> pPrint dir+  pPrint (TarDirDoesNotExist (RegexDir rx)) =+    text "Couldn't find tar dir via regex:" <+> pPrint rx  instance HFErrorProject TarDirDoesNotExist where   eBase _ = 190@@ -469,7 +517,7 @@  -- | File digest verification failed. data DigestError = DigestError FilePath Text Text-  deriving Show+  deriving (Show)  instance Pretty DigestError where   pPrint (DigestError fp currentDigest expectedDigest) =@@ -482,7 +530,7 @@   eDesc _ = "File digest verification failed"  -- | File PGP verification failed.-data GPGError = forall xs . (ToVariantMaybe DownloadFailed xs, PopVariant DownloadFailed xs, Show (V xs), Pretty (V xs)) => GPGError (V xs)+data GPGError = forall xs. (ToVariantMaybe DownloadFailed xs, PopVariant DownloadFailed xs, Show (V xs), Pretty (V xs)) => GPGError (V xs)  deriving instance Show GPGError @@ -495,7 +543,7 @@  -- | Unexpected HTTP status. data HTTPStatusError = HTTPStatusError Int (M.Map (CI ByteString) ByteString)-  deriving Show+  deriving (Show)  instance Pretty HTTPStatusError where   pPrint (HTTPStatusError status _) =@@ -507,7 +555,7 @@  -- | Malformed headers. data MalformedHeaders = MalformedHeaders Text-  deriving Show+  deriving (Show)  instance Pretty MalformedHeaders where   pPrint (MalformedHeaders h) =@@ -519,7 +567,7 @@  -- | Unexpected HTTP status. data HTTPNotModified = HTTPNotModified Text-  deriving Show+  deriving (Show)  instance Pretty HTTPNotModified where   pPrint (HTTPNotModified etag) =@@ -530,8 +578,9 @@   eDesc _ = "Not modified HTTP status error (e.g. during downloads)."  -- | The 'Location' header was expected during a 3xx redirect, but not found.-data NoLocationHeader = NoLocationHeader-  deriving Show+data NoLocationHeader+  = NoLocationHeader+  deriving (Show)  instance Pretty NoLocationHeader where   pPrint NoLocationHeader =@@ -542,8 +591,9 @@   eDesc _ = "The 'Location' header was expected during a 3xx redirect, but not found."  -- | Too many redirects.-data TooManyRedirs = TooManyRedirs-  deriving Show+data TooManyRedirs+  = TooManyRedirs+  deriving (Show)  instance Pretty TooManyRedirs where   pPrint TooManyRedirs =@@ -554,8 +604,9 @@   eDesc _ = "Too many redirections."  -- | A patch could not be applied.-data PatchFailed = PatchFailed-  deriving Show+data PatchFailed+  = PatchFailed+  deriving (Show)  instance Pretty PatchFailed where   pPrint PatchFailed =@@ -566,8 +617,9 @@   eDesc _ = "A patch could not be applied."  -- | The tool requirements could not be found.-data NoToolRequirements = NoToolRequirements-  deriving Show+data NoToolRequirements+  = NoToolRequirements+  deriving (Show)  instance Pretty NoToolRequirements where   pPrint NoToolRequirements =@@ -578,7 +630,7 @@   eDesc _ = "The Tool requirements could not be found."  data InvalidBuildConfig = InvalidBuildConfig Text-  deriving Show+  deriving (Show)  instance Pretty InvalidBuildConfig where   pPrint (InvalidBuildConfig reason) =@@ -588,19 +640,22 @@   eBase _ = 290   eDesc _ = "The build config is invalid." -data NoToolVersionSet = NoToolVersionSet Tool-  deriving Show+data NoToolVersionSet = NoToolVersionSet Tool (Maybe Text)+  deriving (Show)  instance Pretty NoToolVersionSet where-  pPrint (NoToolVersionSet tool) =-    text "No version is set for tool" <+> pPrint tool <+> text "."+  pPrint (NoToolVersionSet tool Nothing) =+    text "No version is set for tool" <+> pPrint tool+  pPrint (NoToolVersionSet tool (Just target)) =+    text "No version is set for tool" <+> pPrint tool <+> text "cross target" <+> text (T.unpack target)  instance HFErrorProject NoToolVersionSet where   eBase _ = 300   eDesc _ = "No version is set for tool (but was expected)." -data NoNetwork = NoNetwork-  deriving Show+data NoNetwork+  = NoNetwork+  deriving (Show)  instance Pretty NoNetwork where   pPrint NoNetwork =@@ -610,8 +665,9 @@   eBase _ = 310   eDesc _ = "A download was required or requested, but '--offline' was specified." -data HadrianNotFound = HadrianNotFound-  deriving Show+data HadrianNotFound+  = HadrianNotFound+  deriving (Show)  instance Pretty HadrianNotFound where   pPrint HadrianNotFound =@@ -621,25 +677,21 @@   eBase _ = 320   eDesc _ = "Could not find Hadrian build files. Does this GHC version support Hadrian builds?" -data ToolShadowed = ToolShadowed-                       Tool-                       FilePath  -- shadow binary-                       FilePath  -- upgraded binary-                       Version   -- upgraded version-  deriving Show+data ToolShadowed = ToolShadowed Tool Version [(FilePath, FilePath)]+  -- upgraded version+  deriving (Show)  instance Pretty ToolShadowed where-  pPrint (ToolShadowed tool sh up _) =+  pPrint (ToolShadowed tool ver shadows) =     text (prettyShow tool-         <> " is shadowed by "-         <> sh-         <> ".\nThe upgrade will not be in effect, unless you remove "-         <> sh-         <> "\nor make sure "-         <> takeDirectory up-         <> " comes before "-         <> takeDirectory sh-         <> " in PATH."+         <> " version " <> T.unpack (prettyVer ver)+         <> " has shadowed binaries:\n"+         <> intercalate "\n" (shadows <&> \(sh, bin) ->+              "  * " <> bin <> " shadowed by " <> sh+           )+         <> ".\nThe upgrade will not be in effect, unless you make sure that "+         <> (takeDirectory . snd . head $ shadows)+         <> " comes first in PATH."          )  instance HFErrorProject ToolShadowed where@@ -648,7 +700,7 @@  -- | File content length verification failed. data ContentLengthError = ContentLengthError (Maybe FilePath) (Maybe Integer) Integer-  deriving Show+  deriving (Show)  instance Pretty ContentLengthError where   pPrint (ContentLengthError Nothing Nothing expectedSize) =@@ -674,7 +726,7 @@   eDesc _ = "File content length verification failed"  data DuplicateReleaseChannel = DuplicateReleaseChannel NewURLSource-  deriving Show+  deriving (Show)  instance HFErrorProject DuplicateReleaseChannel where   eBase _ = 350@@ -687,7 +739,7 @@       <> "\nGiving up. You can use '--force' to remove and append the duplicate source (this may change order/semantics)."  data UnsupportedSetupCombo = UnsupportedSetupCombo Architecture Platform-  deriving Show+  deriving (Show)  instance Pretty UnsupportedSetupCombo where   pPrint (UnsupportedSetupCombo arch plat) =@@ -697,18 +749,29 @@   eBase _ = 360   eDesc _ = "Could not find a compatible setup combo" +data UnsupportedMetadataFormat = UnsupportedMetadataFormat FilePath+  deriving (Show)++instance Pretty UnsupportedMetadataFormat where+  pPrint (UnsupportedMetadataFormat ext) =+    text "Unsupported file extension for metadata:" <+> pPrint ext++instance HFErrorProject UnsupportedMetadataFormat where+  eBase _ = 370+  eDesc _ = "Unsupported file extension for metadata"+     -------------------------     --[ High-level errors ]--     -------------------------  -- | A download failed. The underlying error is encapsulated.-data DownloadFailed = forall xs . (HFErrorProject (V xs), ToVariantMaybe DownloadFailed xs, PopVariant DownloadFailed xs, Show (V xs), Pretty (V xs)) => DownloadFailed (V xs)+data DownloadFailed = forall xs. (HFErrorProject (V xs), ToVariantMaybe DownloadFailed xs, PopVariant DownloadFailed xs, Show (V xs), Pretty (V xs)) => DownloadFailed (V xs)  instance Pretty DownloadFailed where   pPrint (DownloadFailed reason) =     case reason of       VMaybe (_ :: DownloadFailed) -> pPrint reason-      _ -> text "Download failed:" <+> pPrint reason+      _                            -> text "Download failed:" <+> pPrint reason  deriving instance Show DownloadFailed @@ -717,7 +780,7 @@   eNum (DownloadFailed xs) = 5000 + eNum xs   eDesc _ = "A download failed." -data InstallSetError = forall xs1 xs2 . (Show (V xs1), Pretty (V xs1), HFErrorProject (V xs1), Show (V xs2), Pretty (V xs2), HFErrorProject (V xs2)) => InstallSetError (V xs1) (V xs2)+data InstallSetError = forall xs1 xs2. (Show (V xs1), Pretty (V xs1), HFErrorProject (V xs1), Show (V xs2), Pretty (V xs2), HFErrorProject (V xs2)) => InstallSetError (V xs1) (V xs2)  instance Pretty InstallSetError where   pPrint (InstallSetError reason1 reason2) =@@ -736,7 +799,7 @@   -- | A test failed.-data TestFailed = forall es . (ToVariantMaybe TestFailed es, PopVariant TestFailed es, Pretty (V es), Show (V es), HFErrorProject (V es)) => TestFailed FilePath (V es)+data TestFailed = forall es. (ToVariantMaybe TestFailed es, PopVariant TestFailed es, Pretty (V es), Show (V es), HFErrorProject (V es)) => TestFailed FilePath (V es)  instance Pretty TestFailed where   pPrint (TestFailed path reason) =@@ -752,7 +815,7 @@   eDesc _ = "The test failed."  -- | A build failed.-data BuildFailed = forall es . (ToVariantMaybe BuildFailed es, PopVariant BuildFailed es, Pretty (V es), Show (V es), HFErrorProject (V es)) => BuildFailed FilePath (V es)+data BuildFailed = forall es. (ToVariantMaybe BuildFailed es, PopVariant BuildFailed es, Pretty (V es), Show (V es), HFErrorProject (V es)) => BuildFailed FilePath (V es)  instance Pretty BuildFailed where   pPrint (BuildFailed path reason) =@@ -769,7 +832,7 @@   -- | Setting the current GHC version failed.-data GHCupSetError = forall es . (ToVariantMaybe GHCupSetError es, PopVariant GHCupSetError es, Show (V es), Pretty (V es), HFErrorProject (V es)) => GHCupSetError (V es)+data GHCupSetError = forall es. (ToVariantMaybe GHCupSetError es, PopVariant GHCupSetError es, Show (V es), Pretty (V es), HFErrorProject (V es)) => GHCupSetError (V es)  instance Pretty GHCupSetError where   pPrint (GHCupSetError reason) =@@ -785,7 +848,7 @@   eDesc _ = "Setting the current version failed."  -- | Executing stacks platform detection failed.-data StackPlatformDetectError = forall es . (ToVariantMaybe StackPlatformDetectError es, PopVariant StackPlatformDetectError es, Show (V es), Pretty (V es), HFErrorProject (V es)) => StackPlatformDetectError (V es)+data StackPlatformDetectError = forall es. (ToVariantMaybe StackPlatformDetectError es, PopVariant StackPlatformDetectError es, Show (V es), Pretty (V es), HFErrorProject (V es)) => StackPlatformDetectError (V es)  instance Pretty StackPlatformDetectError where   pPrint (StackPlatformDetectError reason) =@@ -808,7 +871,7 @@  -- | Parsing failed. data ParseError = ParseError String-  deriving Show+  deriving (Show)  instance Pretty ParseError where   pPrint (ParseError reason) =@@ -822,7 +885,7 @@   data UnexpectedListLength = UnexpectedListLength String-  deriving Show+  deriving (Show)  instance Pretty UnexpectedListLength where   pPrint (UnexpectedListLength reason) =@@ -835,7 +898,7 @@   eDesc _ = "A list had an unexpected length."  data NoUrlBase = NoUrlBase Text-  deriving Show+  deriving (Show)  instance Pretty NoUrlBase where   pPrint (NoUrlBase url) =@@ -848,7 +911,7 @@   eDesc _ = "URL does not have a base filename."  data DigestMissing = DigestMissing Text-  deriving Show+  deriving (Show)  instance Pretty DigestMissing where   pPrint (DigestMissing uri) =@@ -917,25 +980,25 @@   eBase _ = 800    eNum (MalformedScheme NonAlphaLeading) = 801-  eNum (MalformedScheme InvalidChars) = 802-  eNum (MalformedScheme MissingColon) = 803-  eNum MalformedUserInfo   = 804-  eNum MalformedQuery      = 805-  eNum MalformedFragment   = 806-  eNum MalformedHost       = 807-  eNum MalformedPort       = 808-  eNum MalformedPath       = 809-  eNum (OtherError _)      = 810+  eNum (MalformedScheme InvalidChars)    = 802+  eNum (MalformedScheme MissingColon)    = 803+  eNum MalformedUserInfo                 = 804+  eNum MalformedQuery                    = 805+  eNum MalformedFragment                 = 806+  eNum MalformedHost                     = 807+  eNum MalformedPort                     = 808+  eNum MalformedPath                     = 809+  eNum (OtherError _)                    = 810    eDesc _ = "Failed to parse URI."  instance Pretty ArchiveResult where-  pPrint ArchiveFatal = text "Archive result: fatal"+  pPrint ArchiveFatal  = text "Archive result: fatal"   pPrint ArchiveFailed = text "Archive result: failed"-  pPrint ArchiveWarn = text "Archive result: warning"-  pPrint ArchiveRetry = text "Archive result: retry"-  pPrint ArchiveOk = text "Archive result: Ok"-  pPrint ArchiveEOF = text "Archive result: EOF"+  pPrint ArchiveWarn   = text "Archive result: warning"+  pPrint ArchiveRetry  = text "Archive result: retry"+  pPrint ArchiveOk     = text "Archive result: Ok"+  pPrint ArchiveEOF    = text "Archive result: EOF"  instance HFErrorProject ArchiveResult where   eBase _ = 820
− lib/GHCup/GHC.hs
@@ -1,1426 +0,0 @@-{-# LANGUAGE CPP                   #-}-{-# LANGUAGE BangPatterns          #-}-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE FlexibleInstances     #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE QuasiQuotes           #-}-{-# LANGUAGE TemplateHaskell       #-}--{-|-Module      : GHCup.GHC-Description : GHCup installation functions for GHC-Copyright   : (c) Julian Ospald, 2020-License     : LGPL-3.0-Maintainer  : hasufell@hasufell.de-Stability   : experimental-Portability : portable--}-module GHCup.GHC where---import           GHCup.Download-import           GHCup.Errors-import           GHCup.Types-import           GHCup.Types.JSON               ( )-import           GHCup.Types.Optics-import           GHCup.Utils-import           GHCup.Prelude-import           GHCup.Prelude.File-import           GHCup.Prelude.Logger-import           GHCup.Prelude.Process-import           GHCup.Prelude.String.QQ-import           GHCup.Prelude.Version.QQ-import           GHCup.Prelude.MegaParsec--import           Control.Applicative-import           Control.Concurrent             ( threadDelay )-import           Control.Exception.Safe-import           Control.Monad-#if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )-#endif-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-                                         hiding ( throwM )-import           Data.ByteString                ( ByteString )-import           Data.Either-import           Data.List-import           Data.Maybe-import           Data.List.NonEmpty             ( NonEmpty((:|)) )-import           Data.String                    ( fromString )-import           Data.Text                      ( Text )-import           Data.Time.Clock-import           Data.Time.Format.ISO8601-import           Data.Versions                hiding ( patch )-import           GHC.IO.Exception-import           Data.Variant.Excepts-import           Language.Haskell.TH-import           Language.Haskell.TH.Syntax     ( Quasi(qAddDependentFile) )-import           Optics-import           Prelude                 hiding ( abs-                                                , writeFile-                                                )-import           System.Environment-import           System.FilePath-import           System.IO.Error-import           Text.PrettyPrint.HughesPJClass ( prettyShow )-import           Text.Regex.Posix-import           URI.ByteString--import qualified Crypto.Hash.SHA256            as SHA256-import qualified Data.ByteString.Base16        as B16-import qualified Data.ByteString               as B-import qualified Data.ByteString.Lazy          as BL-import qualified Data.Map.Strict               as Map-import qualified Data.Text                     as T-import qualified Data.Text.IO                  as T-import qualified Data.Text.Encoding            as E-import qualified Text.Megaparsec               as MP---data GHCVer = SourceDist Version-            | GitDist GitBranch-            | RemoteDist URI-            deriving (Eq, Show)----    ---------------------    --[ Tool testing ]---    ------------------------testGHCVer :: ( MonadFail m-              , MonadMask m-              , MonadCatch m-              , MonadReader env m-              , HasDirs env-              , HasSettings env-              , HasPlatformReq env-              , HasGHCupInfo env-              , HasLog env-              , MonadResource m-              , MonadIO m-              , MonadUnliftIO m-              )-           => GHCTargetVersion-           -> [T.Text]-           -> Excepts-                '[ DigestError-                 , ContentLengthError-                 , GPGError-                 , DownloadFailed-                 , NoDownload-                 , ArchiveResult-                 , TarDirDoesNotExist-                 , UnknownArchive-                 , TestFailed-                 , URIParseError-                 ]-                m-                ()-testGHCVer ver addMakeArgs = do-  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo--  dlInfo <--    preview (ix GHC % ix ver % viTestDL % _Just) dls-      ?? NoDownload ver GHC Nothing--  liftE $ testGHCBindist dlInfo ver addMakeArgs----testGHCBindist :: ( MonadFail m-                  , MonadMask m-                  , MonadCatch m-                  , MonadReader env m-                  , HasDirs env-                  , HasSettings env-                  , HasPlatformReq env-                  , HasGHCupInfo env-                  , HasLog env-                  , MonadResource m-                  , MonadIO m-                  , MonadUnliftIO m-                  )-               => DownloadInfo-               -> GHCTargetVersion-               -> [T.Text]-               -> Excepts-                    '[ DigestError-                     , ContentLengthError-                     , GPGError-                     , DownloadFailed-                     , NoDownload-                     , ArchiveResult-                     , TarDirDoesNotExist-                     , UnknownArchive-                     , TestFailed-                     , URIParseError-                     ]-                    m-                    ()-testGHCBindist dlinfo ver addMakeArgs = do-  -- download (or use cached version)-  dl <- liftE $ downloadCached dlinfo Nothing--  liftE $ testPackedGHC dl (view dlSubdir dlinfo) ver addMakeArgs---testPackedGHC :: ( MonadMask m-                 , MonadCatch m-                 , MonadReader env m-                 , HasDirs env-                 , HasPlatformReq env-                 , HasSettings env-                 , MonadThrow m-                 , HasLog env-                 , MonadIO m-                 , MonadUnliftIO m-                 , MonadFail m-                 , MonadResource m-                 )-              => FilePath          -- ^ Path to the packed GHC bindist-              -> Maybe TarDir      -- ^ Subdir of the archive-              -> GHCTargetVersion  -- ^ The GHC version-              -> [T.Text]          -- ^ additional make args-              -> Excepts-                   '[ ArchiveResult, UnknownArchive, TarDirDoesNotExist, TestFailed ] m ()-testPackedGHC dl msubdir ver addMakeArgs = do-  -- unpack-  tmpUnpack <- lift mkGhcupTmpDir-  liftE $ cleanUpOnError tmpUnpack (unpackToDir (fromGHCupPath tmpUnpack) dl)--  -- the subdir of the archive where we do the work-  workdir <- maybe (pure tmpUnpack)-                   (liftE . intoSubdir tmpUnpack)-                   msubdir--  reThrowAll @_ @'[ArchiveResult, UnknownArchive, TarDirDoesNotExist, ProcessError]-    (TestFailed (fromGHCupPath workdir)) $ liftE $ runBuildAction tmpUnpack-                         (testUnpackedGHC workdir ver addMakeArgs)--testUnpackedGHC :: ( MonadReader env m-                   , HasDirs env-                   , HasSettings env-                   , MonadThrow m-                   , HasLog env-                   , MonadIO m-                   )-                => GHCupPath         -- ^ Path to the unpacked GHC bindist (where the make file resides)-                -> GHCTargetVersion  -- ^ The GHC version-                -> [T.Text]          -- ^ additional configure args for bindist-                -> Excepts '[ProcessError] m ()-testUnpackedGHC path tver addMakeArgs = do-  lift $ logInfo $ "Testing GHC version " <> tVerToText tver <> "!"-  ghcDir <- lift $ ghcupGHCDir tver-  let ghcBinDir = fromGHCupPath ghcDir </> "bin"-  env <- liftIO $ addToPath [ghcBinDir] False-  let pathVar = if isWindows then "Path" else "PATH"-  forM_ (Map.lookup pathVar . Map.fromList $ env) $ liftIO . setEnv pathVar--  lEM $ make' (fmap T.unpack addMakeArgs)-              (Just $ fromGHCupPath path)-              "ghc-test"-              (Just $ ("STAGE1_GHC", maybe "" (T.unpack . (<> "-")) (_tvTarget tver)-                                     <> "ghc-"-                                     <> T.unpack (prettyVer $ _tvVersion tver)) : env)-  pure ()---    ----------------------    --[ Tool fetching ]---    -------------------------fetchGHCSrc :: ( MonadFail m-               , MonadMask m-               , MonadCatch m-               , MonadReader env m-               , HasDirs env-               , HasSettings env-               , HasPlatformReq env-               , HasGHCupInfo env-               , HasLog env-               , MonadResource m-               , MonadIO m-               , MonadUnliftIO m-               )-            => GHCTargetVersion-            -> Maybe FilePath-            -> Excepts-                 '[ DigestError-                  , ContentLengthError-                  , GPGError-                  , DownloadFailed-                  , NoDownload-                  , URIParseError-                  ]-                 m-                 FilePath-fetchGHCSrc v mfp = do-  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-  dlInfo <--    preview (ix GHC % ix v % viSourceDL % _Just) dls-      ?? NoDownload v GHC Nothing-  liftE $ downloadCached' dlInfo Nothing mfp----    --------------------------    --[ Tool installation ]---    ------------------------------ | Like 'installGHCBin', except takes the 'DownloadInfo' as--- argument instead of looking it up from 'GHCupDownloads'.-installGHCBindist :: ( MonadFail m-                     , MonadMask m-                     , MonadCatch m-                     , MonadReader env m-                     , HasDirs env-                     , HasSettings env-                     , HasPlatformReq env-                     , HasLog env-                     , MonadResource m-                     , MonadIO m-                     , MonadUnliftIO m-                     )-                  => DownloadInfo    -- ^ where/how to download-                  -> GHCTargetVersion -- ^ the version to install-                  -> InstallDir-                  -> Bool            -- ^ Force install-                  -> [T.Text]        -- ^ additional configure args for bindist-                  -> T.Text-                  -> Excepts-                       '[ AlreadyInstalled-                        , BuildFailed-                        , DigestError-                        , ContentLengthError-                        , GPGError-                        , DownloadFailed-                        , NoDownload-                        , NotInstalled-                        , UnknownArchive-                        , TarDirDoesNotExist-                        , DirNotEmpty-                        , ArchiveResult-                        , ProcessError-                        , UninstallFailed-                        , MergeFileTreeError-                        , URIParseError-                        ]-                       m-                       ()-installGHCBindist dlinfo tver installDir forceInstall addConfArgs installTargets = do-  lift $ logDebug $ "Requested to install GHC with " <> tVerToText tver--  regularGHCInstalled <- lift $ ghcInstalled tver--  if-    | not forceInstall-    , regularGHCInstalled-    , GHCupInternal <- installDir -> do-        throwE $ AlreadyInstalled GHC (_tvVersion tver)--    | forceInstall-    , regularGHCInstalled-    , GHCupInternal <- installDir -> do-        lift $ logInfo "Removing the currently installed GHC version first!"-        liftE $ rmGHCVer tver--    | otherwise -> pure ()--  -- download (or use cached version)-  dl <- liftE $ downloadCached dlinfo Nothing---  toolchainSanityChecks--  case installDir of-    IsolateDir isoDir -> do                        -- isolated install-      lift $ logInfo $ "isolated installing GHC to " <> T.pack isoDir-      liftE $ installPackedGHC dl (view dlSubdir dlinfo) (IsolateDirResolved isoDir) tver forceInstall addConfArgs installTargets-    GHCupInternal -> do                            -- regular install-      -- prepare paths-      ghcdir <- lift $ ghcupGHCDir tver--      liftE $ installPackedGHC dl (view dlSubdir dlinfo) (GHCupDir ghcdir) tver forceInstall addConfArgs installTargets--      -- make symlinks & stuff when regular install,-      liftE $ postGHCInstall tver-- where-  toolchainSanityChecks = do-    r <- forM ["CC", "LD"] (liftIO . lookupEnv)-    case catMaybes r of-      [] -> pure ()-      _ -> do-        lift $ logWarn $ "CC/LD environment variable is set. This will change the compiler/linker"-         <> "\n" <> "GHC uses internally and can cause defunct GHC in some cases (e.g. in Anaconda"-         <> "\n" <> "environments). If you encounter problems, unset CC and LD and reinstall."----- | Install a packed GHC distribution. This only deals with unpacking and the GHC--- build system and nothing else.-installPackedGHC :: ( MonadMask m-                    , MonadCatch m-                    , MonadReader env m-                    , HasDirs env-                    , HasPlatformReq env-                    , HasSettings env-                    , MonadThrow m-                    , HasLog env-                    , MonadIO m-                    , MonadUnliftIO m-                    , MonadFail m-                    , MonadResource m-                    )-                 => FilePath          -- ^ Path to the packed GHC bindist-                 -> Maybe TarDir      -- ^ Subdir of the archive-                 -> InstallDirResolved-                 -> GHCTargetVersion  -- ^ The GHC version-                 -> Bool              -- ^ Force install-                 -> [T.Text]          -- ^ additional configure args for bindist-                 -> T.Text-                 -> Excepts-                      '[ BuildFailed-                       , UnknownArchive-                       , TarDirDoesNotExist-                       , DirNotEmpty-                       , ArchiveResult-                       , ProcessError-                       , MergeFileTreeError-                       ] m ()-installPackedGHC dl msubdir inst ver forceInstall addConfArgs installTargets = do-  PlatformRequest {..} <- lift getPlatformReq--  unless forceInstall-    (liftE $ installDestSanityCheck inst)--  -- unpack-  tmpUnpack <- lift mkGhcupTmpDir-  liftE $ cleanUpOnError tmpUnpack (unpackToDir (fromGHCupPath tmpUnpack) dl)-  liftE $ catchWarn $ lEM @_ @'[ProcessError] $ darwinNotarization _rPlatform (fromGHCupPath tmpUnpack)--  -- the subdir of the archive where we do the work-  workdir <- maybe (pure tmpUnpack)-                   (liftE . intoSubdir tmpUnpack)-                   msubdir--  liftE $ runBuildAction tmpUnpack-                         (installUnpackedGHC workdir inst ver forceInstall addConfArgs installTargets)----- | Install an unpacked GHC distribution. This only deals with the GHC--- build system and nothing else.-installUnpackedGHC :: ( MonadReader env m-                      , HasPlatformReq env-                      , HasDirs env-                      , HasSettings env-                      , MonadThrow m-                      , HasLog env-                      , MonadIO m-                      , MonadUnliftIO m-                      , MonadMask m-                      , MonadResource m-                      , MonadFail m-                      )-                   => GHCupPath           -- ^ Path to the unpacked GHC bindist (where the configure script resides)-                   -> InstallDirResolved  -- ^ Path to install to-                   -> GHCTargetVersion    -- ^ The GHC version-                   -> Bool                -- ^ Force install-                   -> [T.Text]          -- ^ additional configure args for bindist-                   -> T.Text-                   -> Excepts '[ProcessError, MergeFileTreeError] m ()-installUnpackedGHC path inst tver forceInstall addConfArgs installTargets-  | isWindows = do-      lift $ logInfo "Installing GHC (this may take a while)"-      -- Windows bindists are relocatable and don't need-      -- to run configure.-      -- We also must make sure to preserve mtime to not confuse ghc-pkg.-      liftE $ mergeGHCFileTree path inst tver forceInstall-  | otherwise = do-      PlatformRequest {..} <- lift getPlatformReq-      Settings {..} <- lift getSettings--      addConfArgs' <- sanitizefGHCconfOptions (T.unpack <$> addConfArgs)-      defGHCConfOptions' <- sanitizefGHCconfOptions defGHCConfOptions--      lift $ logInfo "Installing GHC (this may take a while)"-      lEM $ execLogged "sh"-                       ("./configure" : ("--prefix=" <> fromInstallDir inst)-                        : (maybe mempty (\x -> ["--target=" <> T.unpack x]) (_tvTarget tver)-                          <> ldOverride (_tvVersion tver) _rPlatform-                          <> defGHCConfOptions'-                          <> addConfArgs')-                       )-                       (Just $ fromGHCupPath path)-                       "ghc-configure"-                       Nothing-      tmpInstallDest <- lift withGHCupTmpDir-      lEM $ make (["DESTDIR=" <> fromGHCupPath tmpInstallDest] <> (T.unpack <$> withStripTarget (_tvVersion tver) _rPlatform)) (Just $ fromGHCupPath path)-      liftE $ catchWarn $ lEM @_ @'[ProcessError] $ darwinNotarization _rPlatform (fromGHCupPath tmpInstallDest)-      liftE $ mergeGHCFileTree (tmpInstallDest `appendGHCupPath` dropDrive (fromInstallDir inst)) inst tver forceInstall-      pure ()- where-  installTargets' = T.words installTargets--  -- https://github.com/haskell/ghcup-hs/issues/319-  withStripTarget ver plat-    | ver >= [vver|7.10.0|]-    , ver <  [vver|8.3.0|]-    , Linux _ <- plat-    = "STRIP_CMD=true":installTargets'-    | otherwise-    = installTargets'----mergeGHCFileTree :: ( MonadReader env m-                    , HasPlatformReq env-                    , HasDirs env-                    , HasSettings env-                    , MonadThrow m-                    , HasLog env-                    , MonadIO m-                    , MonadUnliftIO m-                    , MonadMask m-                    , MonadResource m-                    , MonadFail m-                    )-                 => GHCupPath           -- ^ Path to the root of the tree-                 -> InstallDirResolved  -- ^ Path to install to-                 -> GHCTargetVersion    -- ^ The GHC version-                 -> Bool                -- ^ Force install-                 -> Excepts '[MergeFileTreeError] m ()-mergeGHCFileTree root inst tver forceInstall-  | isWindows = do-      liftE $ mergeFileTree root inst GHC tver $ \source dest -> do-        mtime <- liftIO $ ifM (pathIsSymbolicLink source) (pure Nothing) (Just <$> getModificationTime source)-        when forceInstall $ hideError doesNotExistErrorType $ hideError InappropriateType $ recycleFile dest-        liftIO $ moveFilePortable source dest-        forM_ mtime $ liftIO . setModificationTime dest-  | otherwise = do-      liftE $ mergeFileTree root-        inst-        GHC-        tver-        (\f t -> liftIO $ do-            mtime <- ifM (pathIsSymbolicLink f) (pure Nothing) (Just <$> getModificationTime f)-            install f t (not forceInstall)-            forM_ mtime $ setModificationTime t)----- | Installs GHC into @~\/.ghcup\/ghc/\<ver\>@ and places the--- following symlinks in @~\/.ghcup\/bin@:------   * @ghc-x.y.z -> ..\/ghc\/x.y.z\/bin/ghc@---   * @ghc-x.y   -> ..\/ghc\/x.y.z\/bin/ghc@ (if x.y.z is the latest x.y version)-installGHCBin :: ( MonadFail m-                 , MonadMask m-                 , MonadCatch m-                 , MonadReader env m-                 , HasPlatformReq env-                 , HasGHCupInfo env-                 , HasDirs env-                 , HasSettings env-                 , HasLog env-                 , MonadResource m-                 , MonadIO m-                 , MonadUnliftIO m-                 , Alternative m-                 )-              => GHCTargetVersion -- ^ the version to install-              -> InstallDir-              -> Bool            -- ^ force install-              -> [T.Text]        -- ^ additional configure args for bindist-              -> T.Text-              -> Excepts-                   '[ AlreadyInstalled-                    , BuildFailed-                    , DigestError-                    , ContentLengthError-                    , GPGError-                    , DownloadFailed-                    , NoDownload-                    , NotInstalled-                    , UnknownArchive-                    , TarDirDoesNotExist-                    , DirNotEmpty-                    , ArchiveResult-                    , ProcessError-                    , UninstallFailed-                    , MergeFileTreeError-                    , NoCompatiblePlatform-                    , ParseError-                    , UnsupportedSetupCombo-                    , DistroNotFound-                    , NoCompatibleArch-                    , URIParseError-                    ]-                   m-                   ()-installGHCBin tver installDir forceInstall addConfArgs installTargets = do-  dlinfo <- liftE $ getDownloadInfo' GHC tver-  liftE $ installGHCBindist dlinfo tver installDir forceInstall addConfArgs installTargets------    ----------------    --[ Set GHC ]---    --------------------- | Set GHC symlinks in @~\/.ghcup\/bin@ for the requested GHC version. The behavior depends--- on `SetGHC`:------   * SetGHCOnly: @~\/.ghcup\/bin\/ghc -> ~\/.ghcup\/ghc\/\<ver\>\/bin\/ghc@---   * SetGHC_XY: @~\/.ghcup\/bin\/ghc-X.Y -> ~\/.ghcup\/ghc\/\<ver\>\/bin\/ghc@---   * SetGHC_XYZ: @~\/.ghcup\/bin\/ghc-\<ver\> -> ~\/.ghcup\/ghc\/\<ver\>\/bin\/ghc@------ Additionally creates a @~\/.ghcup\/share -> ~\/.ghcup\/ghc\/\<ver\>\/share symlink@--- for 'SetGHCOnly' constructor.-setGHC :: ( MonadReader env m-          , HasDirs env-          , HasLog env-          , MonadThrow m-          , MonadFail m-          , MonadIO m-          , MonadCatch m-          , MonadMask m-          , MonadUnliftIO m-          )-       => GHCTargetVersion-       -> SetGHC-       -> Maybe FilePath  -- if set, signals that we're not operating in ~/.ghcup/bin-                          -- and don't want mess with other versions-       -> Excepts '[NotInstalled] m GHCTargetVersion-setGHC ver sghc mBinDir = do-  let verS = T.unpack $ prettyVer (_tvVersion ver)-  ghcdir                        <- lift $ ghcupGHCDir ver--  whenM (lift $ not <$> ghcInstalled ver) (throwE (NotInstalled GHC ver))--  -- symlink destination-  binDir <- case mBinDir of-    Just x -> pure x-    Nothing -> do-      Dirs {binDir = f} <- lift getDirs-      pure f--  -- first delete the old symlinks (this fixes compatibility issues-  -- with old ghcup)-  when (isNothing mBinDir) $-    case sghc of-      SetGHCOnly -> liftE $ rmPlainGHC (_tvTarget ver)-      SetGHC_XY  -> liftE $ rmMajorGHCSymlinks ver-      SetGHC_XYZ -> liftE $ rmMinorGHCSymlinks ver--  -- for ghc tools (ghc, ghci, haddock, ...)-  verfiles <- ghcToolFiles ver-  forM_ verfiles $ \file -> do-    mTargetFile <- case sghc of-      SetGHCOnly -> pure $ Just file-      SetGHC_XY  -> do-        handle-            (\(e :: ParseError) -> lift $ logWarn (T.pack $ displayException e) >> pure Nothing)-          $ do-            (mj, mi) <- getMajorMinorV (_tvVersion ver)-            let major' = intToText mj <> "." <> intToText mi-            pure $ Just (file <> "-" <> T.unpack major')-      SetGHC_XYZ ->-        pure $ Just (file <> "-" <> verS)--    -- create symlink-    forM_ mTargetFile $ \targetFile -> do-      bindir <- ghcInternalBinDir ver-      let fullF = binDir </> targetFile  <> exeExt-          fileWithExt = bindir </> file <> exeExt-      destL <- binarySymLinkDestination binDir fileWithExt-      lift $ createLink destL fullF--      when (targetFile == "ghc") $-        liftIO (isShadowed fullF) >>= \case-          Nothing -> pure ()-          Just pa -> lift $ logWarn $ T.pack $ prettyHFError (ToolShadowed GHC pa fullF (_tvVersion ver))--  when (isNothing mBinDir) $ do-    -- create symlink for share dir-    when (isNothing . _tvTarget $ ver) $ lift $ symlinkShareDir (fromGHCupPath ghcdir) verS--    when (sghc == SetGHCOnly) $ lift warnAboutHlsCompatibility--  pure ver-- where--  symlinkShareDir :: ( MonadReader env m-                     , HasDirs env-                     , MonadIO m-                     , HasLog env-                     , MonadCatch m-                     , MonadMask m-                     )-                  => FilePath-                  -> String-                  -> m ()-  symlinkShareDir ghcdir ver' = do-    Dirs {..} <- getDirs-    let destdir = fromGHCupPath baseDir-    case sghc of-      SetGHCOnly -> do-        let sharedir     = "share"-        let fullsharedir = ghcdir </> sharedir-        logDebug $ "Checking for sharedir existence: " <> T.pack fullsharedir-        whenM (liftIO $ doesDirectoryExist fullsharedir) $ do-          let fullF   = destdir </> sharedir-          let targetF = "." </> "ghc" </> ver' </> sharedir-          logDebug $ "rm -f " <> T.pack fullF-          hideError doesNotExistErrorType $ rmDirectoryLink fullF-          logDebug $ "ln -s " <> T.pack targetF <> " " <> T.pack fullF--          if isWindows-          then liftIO-                 -- On windows we need to be more permissive-                 -- in case symlinks can't be created, be just-                 -- give up here. This symlink isn't strictly necessary.-                 $ hideError permissionErrorType-                 $ hideError illegalOperationErrorType-                 $ createDirectoryLink targetF fullF-          else liftIO-                 $ createDirectoryLink targetF fullF-      _ -> pure ()--unsetGHC :: ( MonadReader env m-            , HasDirs env-            , HasLog env-            , MonadThrow m-            , MonadFail m-            , MonadIO m-            , MonadMask m-            )-         => Maybe Text-         -> Excepts '[NotInstalled] m ()-unsetGHC = rmPlainGHC------    ---------------    --[ GHC rm ]---    ------------------- | Delete a ghc version and all its symlinks.------ This may leave GHCup without a "set" version.--- Will try to fix the ghc-x.y symlink after removal (e.g. to an--- older version).-rmGHCVer :: ( MonadReader env m-            , HasDirs env-            , MonadThrow m-            , HasLog env-            , MonadIO m-            , MonadFail m-            , MonadCatch m-            , MonadMask m-            , MonadUnliftIO m-            )-         => GHCTargetVersion-         -> Excepts '[NotInstalled, UninstallFailed] m ()-rmGHCVer ver = do-  isSetGHC <- lift $ fmap (== Just ver) $ ghcSet (_tvTarget ver)--  whenM (lift $ fmap not $ ghcInstalled ver) (throwE (NotInstalled GHC ver))--  -- this isn't atomic, order matters-  when isSetGHC $ do-    lift $ logInfo "Removing ghc symlinks"-    liftE $ rmPlainGHC (_tvTarget ver)--  lift $ logInfo "Removing ghc-x.y.z symlinks"-  liftE $ rmMinorGHCSymlinks ver--  lift $ logInfo "Removing/rewiring ghc-x.y symlinks"-  -- first remove-  handle (\(_ :: ParseError) -> pure ()) $ liftE $ rmMajorGHCSymlinks ver-  -- then fix them (e.g. with an earlier version)--  dir' <- lift $ ghcupGHCDir ver-  let dir = fromGHCupPath dir'-  lift (getInstalledFiles GHC ver) >>= \case-    Just files -> do-      lift $ logInfo $ "Removing files safely from: " <> T.pack dir-      forM_ files (lift . hideError NoSuchThing . recycleFile . (\f -> dir </> dropDrive f))-      hideError UnsatisfiedConstraints $ removeEmptyDirsRecursive dir-      survivors <- liftIO $ hideErrorDef [doesNotExistErrorType] [] $ listDirectory dir-      f <- recordedInstallationFile GHC ver-      lift $ recycleFile f-      when (not (null survivors)) $ throwE $ UninstallFailed dir survivors-    Nothing -> do-      isDir <- liftIO $ doesDirectoryExist dir-      isSyml <- liftIO $ handleIO (\_ -> pure False) $ pathIsSymbolicLink dir-      when (isDir && not isSyml) $ do-        lift $ logInfo $ "Removing legacy directory recursively: " <> T.pack dir-        recyclePathForcibly dir'--  v' <--    handle-      (\(e :: ParseError) -> lift $ logWarn (T.pack $ displayException e) >> pure Nothing)-    $ fmap Just-    $ getMajorMinorV (_tvVersion ver)-  forM_ v' $ \(mj, mi) -> lift (getGHCForPVP (PVP (fromIntegral mj :| [fromIntegral mi])) (_tvTarget ver))-    >>= mapM_ (\v -> liftE $ setGHC v SetGHC_XY Nothing)--  Dirs {..} <- lift getDirs--  when isSetGHC $ do-    lift $ hideError doesNotExistErrorType $ rmDirectoryLink (fromGHCupPath baseDir </> "share")-----    ----------------    --[ Compile ]---    -------------------- | Compile a GHC from source. This behaves wrt symlinks and installation--- the same as 'installGHCBin'.-compileGHC :: ( MonadMask m-              , MonadReader env m-              , HasDirs env-              , HasPlatformReq env-              , HasGHCupInfo env-              , HasSettings env-              , MonadThrow m-              , MonadResource m-              , HasLog env-              , MonadIO m-              , MonadUnliftIO m-              , MonadFail m-              )-           => GHCVer-           -> Maybe Text               -- ^ cross target-           -> Maybe [VersionPattern]-           -> Either Version FilePath  -- ^ GHC version to bootstrap with-           -> Maybe (Either Version FilePath)  -- ^ GHC version to compile hadrian with-           -> Maybe Int                -- ^ jobs-           -> Maybe FilePath           -- ^ build config-           -> Maybe (Either FilePath [URI])  -- ^ patches-           -> [Text]                   -- ^ additional args to ./configure-           -> Maybe String             -- ^ build flavour-           -> Maybe BuildSystem-           -> InstallDir-           -> T.Text-           -> Excepts-                '[ AlreadyInstalled-                 , BuildFailed-                 , DigestError-                 , ContentLengthError-                 , GPGError-                 , DownloadFailed-                 , GHCupSetError-                 , NoDownload-                 , NotFoundInPATH-                 , PatchFailed-                 , UnknownArchive-                 , TarDirDoesNotExist-                 , NotInstalled-                 , DirNotEmpty-                 , ArchiveResult-                 , FileDoesNotExistError-                 , HadrianNotFound-                 , InvalidBuildConfig-                 , ProcessError-                 , CopyError-                 , BuildFailed-                 , UninstallFailed-                 , MergeFileTreeError-                 , URIParseError-                 ]-                m-                GHCTargetVersion-compileGHC targetGhc crossTarget vps bstrap hghc jobs mbuildConfig patches aargs buildFlavour buildSystem installDir installTargets-  = do-    pfreq@PlatformRequest { .. } <- lift getPlatformReq-    GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo--    (workdir, tmpUnpack, tver, ov) <- case targetGhc of-      -- unpack from version tarball-      SourceDist ver -> do-        lift $ logDebug $ "Requested to compile: " <> prettyVer ver <> " with " <> either prettyVer T.pack bstrap--        -- download source tarball-        let tver = mkTVer ver-        dlInfo <--          preview (ix GHC % ix tver % viSourceDL % _Just) dls-            ?? NoDownload tver GHC (Just pfreq)-        dl <- liftE $ downloadCached dlInfo Nothing--        -- unpack-        tmpUnpack <- lift mkGhcupTmpDir-        liftE $ cleanUpOnError tmpUnpack (unpackToDir (fromGHCupPath tmpUnpack) dl)-        liftE $ catchWarn $ lEM @_ @'[ProcessError] $ darwinNotarization _rPlatform $ fromGHCupPath tmpUnpack--        workdir <- maybe (pure tmpUnpack)-                         (liftE . intoSubdir tmpUnpack)-                         (view dlSubdir dlInfo)-        liftE $ applyAnyPatch patches (fromGHCupPath workdir)--        ov <- case vps of-                Just vps' -> fmap Just $ expandVersionPattern (Just ver) "" "" "" "" vps'-                Nothing   -> pure Nothing--        pure (workdir, tmpUnpack, Just (GHCTargetVersion crossTarget ver), ov)--      RemoteDist uri -> do-        lift $ logDebug $ "Requested to compile (from uri): " <> T.pack (show uri)--        -- download source tarball-        tmpDownload <- lift withGHCupTmpDir-        tmpUnpack <- lift mkGhcupTmpDir-        tar <- liftE $ download uri Nothing Nothing Nothing (fromGHCupPath tmpDownload) Nothing False-        (bf, tver) <- liftE $ cleanUpOnError @'[UnknownArchive, ArchiveResult, ProcessError] tmpUnpack $ do-          liftE $ unpackToDir (fromGHCupPath tmpUnpack) tar-          let regex = [s|^(.*/)*boot$|] :: B.ByteString-          [bootFile] <- liftIO $ findFilesDeep-            tmpUnpack-            (makeRegexOpts compExtended-                           execBlank-                           regex-            )-          tver <- liftE $ catchAllE @_ @'[ProcessError, ParseError, NotFoundInPATH] @'[] (\_ -> pure Nothing) $ fmap Just $ getGHCVer-            (appendGHCupPath tmpUnpack (takeDirectory bootFile))-          pure (bootFile, tver)--        let workdir = appendGHCupPath tmpUnpack (takeDirectory bf)--        ov <- case vps of-                Just vps' -> fmap Just $ expandVersionPattern tver "" "" "" "" vps'-                Nothing   -> pure Nothing--        pure (workdir, tmpUnpack, GHCTargetVersion crossTarget <$> tver, ov)--      -- clone from git-      GitDist GitBranch{..} -> do-        tmpUnpack <- lift mkGhcupTmpDir-        let git args = execLogged "git" ("--no-pager":args) (Just $ fromGHCupPath tmpUnpack) "git" Nothing-        (tver, ov) <- cleanUpOnError tmpUnpack $ reThrowAll @_ @'[PatchFailed, ProcessError, NotFoundInPATH, DigestError, ContentLengthError, DownloadFailed, GPGError] DownloadFailed $ do-          let rep = fromMaybe "https://gitlab.haskell.org/ghc/ghc.git" repo-          lift $ logInfo $ "Fetching git repo " <> T.pack rep <> " at ref " <> T.pack ref <> " (this may take a while)"-          lEM $ git [ "init" ]-          lEM $ git [ "remote"-                    , "add"-                    , "origin"-                    , fromString rep ]--          -- figure out if we can do a shallow clone-          remoteBranches <- catchE @ProcessError @'[PatchFailed, ProcessError, NotFoundInPATH, DigestError, ContentLengthError, DownloadFailed, GPGError] @'[PatchFailed, NotFoundInPATH, DigestError, DownloadFailed, GPGError] (\(_ :: ProcessError) -> pure [])-              $ fmap processBranches $ gitOut ["ls-remote", "--heads", "origin"] (fromGHCupPath tmpUnpack)-          let shallow_clone-                | isCommitHash ref                     = True-                | fromString ref `elem` remoteBranches = True-                | otherwise                            = False-          lift $ logDebug $ "Shallow clone: " <> T.pack (show shallow_clone)--          -- fetch-          let fetch_args-                | shallow_clone = ["fetch", "--depth", "1", "--quiet", "origin", fromString ref]-                | otherwise     = ["fetch", "--tags",       "--quiet", "origin"                ]-          lEM $ git fetch_args--          -- initial checkout-          lEM $ git [ "checkout", fromString ref ]--          -- gather some info-          git_describe <- if shallow_clone-                          then pure Nothing-                          else fmap Just $ liftE $ gitOut ["describe", "--tags"] (fromGHCupPath tmpUnpack)-          chash <- liftE $ gitOut ["rev-parse", "HEAD" ] (fromGHCupPath tmpUnpack)-          branch <- liftE $ gitOut ["rev-parse", "--abbrev-ref", "HEAD" ] (fromGHCupPath tmpUnpack)--          -- clone submodules-          lEM $ git [ "submodule", "update", "--init", "--depth", "1" ]--          -- apply patches-          liftE $ applyAnyPatch patches (fromGHCupPath tmpUnpack)--          -- bootstrap-          tver <- liftE $ catchAllE @_ @'[ProcessError, ParseError, NotFoundInPATH] @'[] (\_ -> pure Nothing) $ fmap Just $ getGHCVer-            tmpUnpack-          liftE $ catchWarn $ lEM @_ @'[ProcessError] $ darwinNotarization _rPlatform (fromGHCupPath tmpUnpack)-          lift $ logInfo $ "Examining git ref " <> T.pack ref <> "\n  " <>-                           "GHC version (from Makefile): " <> T.pack (show (prettyVer <$> tver)) <>-                           (if not shallow_clone then "\n  " <> "'git describe' output: " <> fromJust git_describe else mempty) <>-                           (if isCommitHash ref then mempty else "\n  " <> "commit hash: " <> chash)-          liftIO $ threadDelay 5000000 -- give the user a sec to intervene--          ov <- case vps of-                  Just vps' -> fmap Just $ expandVersionPattern-                                             tver-                                             (take 7 $ T.unpack chash)-                                             (T.unpack chash)-                                             (maybe "" T.unpack git_describe)-                                             (T.unpack branch)-                                             vps'-                  Nothing -> pure Nothing--          pure (tver, ov)--        pure (tmpUnpack, tmpUnpack, GHCTargetVersion crossTarget <$> tver, ov)-    -- the version that's installed may differ from the-    -- compiled version, so the user can overwrite it-    installVer <- if | Just ov'   <- ov   -> pure (GHCTargetVersion crossTarget ov')-                     | Just tver' <- tver -> pure tver'-                     | otherwise          -> fail "No GHC version given and couldn't detect version. Giving up..."--    alreadyInstalled <- lift $ ghcInstalled installVer-    alreadySet <- fmap (== Just installVer) $ lift $ ghcSet (_tvTarget installVer)--    when alreadyInstalled $ do-      case installDir of-        IsolateDir isoDir ->-          lift $ logWarn $ "GHC " <> T.pack (prettyShow installVer) <> " already installed. Isolate installing to " <> T.pack isoDir-        GHCupInternal ->-          lift $ logWarn $ "GHC " <> T.pack (prettyShow installVer) <> " already installed. Will overwrite existing version."-      lift $ logWarn-        "...waiting for 10 seconds before continuing, you can still abort..."-      liftIO $ threadDelay 10000000 -- give the user a sec to intervene--    ghcdir <- case installDir of-      IsolateDir isoDir -> pure $ IsolateDirResolved isoDir-      GHCupInternal -> GHCupDir <$> lift (ghcupGHCDir installVer)--    mBindist <- liftE $ runBuildAction-      tmpUnpack-      (do-        -- prefer 'tver', because the real version carries out compatibility checks-        -- we don't want the user to do funny things with it-        let doHadrian = compileHadrianBindist (fromMaybe installVer tver) (fromGHCupPath workdir) ghcdir-            doMake    = compileMakeBindist (fromMaybe installVer tver) (fromGHCupPath workdir) ghcdir-        case buildSystem of-          Just Hadrian -> do-            lift $ logInfo "Requested to use Hadrian"-            liftE doHadrian-          Just Make -> do-            lift $ logInfo "Requested to use Make"-            doMake-          Nothing -> do-            supportsHadrian <- liftE $ catchE @HadrianNotFound @'[HadrianNotFound] @'[] (\_ -> return False)-                                 $ fmap (const True)-                                 $ findHadrianFile (fromGHCupPath workdir)-            if supportsHadrian-            then do-              lift $ logInfo "Detected Hadrian"-              liftE doHadrian-            else do-              lift $ logInfo "Detected Make"-              doMake-      )--    case installDir of-      GHCupInternal ->-        -- only remove old ghc in regular installs-        when alreadyInstalled $ do-          lift $ logInfo "Deleting existing installation"-          liftE $ rmGHCVer installVer--      _ -> pure ()--    forM_ mBindist $ \bindist -> do-      liftE $ installPackedGHC bindist-                               (Just $ RegexDir "ghc-.*")-                               ghcdir-                               installVer-                               False       -- not a force install, since we already overwrite when compiling.-                               []-                               installTargets--    case installDir of-      -- set and make symlinks for regular (non-isolated) installs-      GHCupInternal -> do-        reThrowAll GHCupSetError $ postGHCInstall installVer-        -- restore-        when alreadySet $ liftE $ void $ setGHC installVer SetGHCOnly Nothing--      _ -> pure ()--    pure installVer-- where-  getGHCVer :: ( MonadReader env m-               , HasSettings env-               , HasDirs env-               , HasLog env-               , MonadIO m-               , MonadThrow m-               )-            => GHCupPath-            -> Excepts '[ProcessError, ParseError, NotFoundInPATH] m Version-  getGHCVer tmpUnpack = do-    lEM $ execLogged "python3" ["./boot"] (Just $ fromGHCupPath tmpUnpack) "ghc-bootstrap" Nothing-    liftE $ configureWithGhcBoot Nothing [] (Just $ fromGHCupPath tmpUnpack) "ghc-bootstrap"-    let versionFile = fromGHCupPath tmpUnpack </> "VERSION"-    hasVersionFile <- liftIO $ doesFileExist versionFile-    if hasVersionFile-    then do-      lift $ logDebug "Detected VERSION file, trying to extract"-      contents <- liftIO $ readFile versionFile-      either (throwE . ParseError . show) pure . MP.parse version' "" . T.pack . stripNewlineEnd $ contents-    else do-      lift $ logDebug "Didn't detect VERSION file, trying to extract via legacy 'make'"-      CapturedProcess {..} <- lift $ makeOut-        ["show!", "--quiet", "VALUE=ProjectVersion" ] (Just $ fromGHCupPath tmpUnpack)-      case _exitCode of-        ExitSuccess -> either (throwE . ParseError . show) pure . MP.parse ghcProjectVersion "" . T.pack . stripNewlineEnd . T.unpack . decUTF8Safe' $ _stdOut-        ExitFailure c -> throwE $ NonZeroExit c "make" ["show!", "--quiet", "VALUE=ProjectVersion" ]--  defaultConf =-    let cross_mk = $(LitE . StringL <$> (qAddDependentFile "data/build_mk/cross" >> runIO (readFile "data/build_mk/cross")))-        default_mk = $(LitE . StringL <$> (qAddDependentFile "data/build_mk/default" >> runIO (readFile "data/build_mk/default")))-    in case crossTarget of-         Just _ -> cross_mk-         _      -> default_mk--  compileHadrianBindist :: ( MonadReader env m-                           , HasDirs env-                           , HasSettings env-                           , HasPlatformReq env-                           , MonadThrow m-                           , MonadCatch m-                           , HasLog env-                           , MonadIO m-                           , MonadFail m-                           )-                        => GHCTargetVersion-                        -> FilePath-                        -> InstallDirResolved-                        -> Excepts-                             '[ FileDoesNotExistError-                              , HadrianNotFound-                              , InvalidBuildConfig-                              , PatchFailed-                              , ProcessError-                              , NotFoundInPATH-                              , CopyError]-                             m-                             (Maybe FilePath)  -- ^ output path of bindist, None for cross-  compileHadrianBindist tver workdir ghcdir = do-    liftE $ configureBindist tver workdir ghcdir--    lift $ logInfo $ "Building GHC version " <> tVerToText tver <> " (this may take a while)..."-    hadrian_build <- liftE $ findHadrianFile workdir-    hEnv <- case hghc of-              Nothing -> pure Nothing-              Just hghc' -> do-                cEnv <- Map.fromList <$> liftIO getEnvironment-                ghc <- liftE $ resolveGHC hghc'-                pure . Just . Map.toList . Map.insert "GHC" ghc $ cEnv---    lEM $ execLogged hadrian_build-                          ( maybe [] (\j  -> ["-j" <> show j]         ) jobs-                         ++ maybe [] (\bf -> ["--flavour=" <> bf]) buildFlavour-                         ++ ["binary-dist"]-                          )-                          (Just workdir) "ghc-make"-                          hEnv-    [tar] <- liftIO $ findFiles-      (workdir </> "_build" </> "bindist")-      (makeRegexOpts compExtended-                     execBlank-                     ([s|^ghc-.*\.tar\..*$|] :: ByteString)-      )-    liftE $ fmap Just $ copyBindist tver tar (workdir </> "_build" </> "bindist")--  findHadrianFile :: (MonadIO m)-                  => FilePath-                  -> Excepts-                       '[HadrianNotFound]-                       m-                       FilePath-  findHadrianFile workdir = do-    let possible_files = if isWindows-                         then ((workdir </> "hadrian") </>) <$> ["build.bat"]-                         else ((workdir </> "hadrian") </>) <$> ["build", "build.sh"]-    exists <- forM possible_files (\f -> liftIO (doesFileExist f) <&> (,f))-    case filter fst exists of-      [] -> throwE HadrianNotFound-      ((_, x):_) -> pure x--  compileMakeBindist :: ( MonadReader env m-                        , HasDirs env-                        , HasSettings env-                        , HasPlatformReq env-                        , MonadThrow m-                        , MonadCatch m-                        , HasLog env-                        , MonadIO m-                        , MonadFail m-                        , MonadMask m-                        , MonadUnliftIO m-                        , MonadResource m-                        )-                     => GHCTargetVersion-                     -> FilePath-                     -> InstallDirResolved-                     -> Excepts-                          '[ FileDoesNotExistError-                           , HadrianNotFound-                           , InvalidBuildConfig-                           , PatchFailed-                           , ProcessError-                           , NotFoundInPATH-                           , MergeFileTreeError-                           , CopyError]-                          m-                       (Maybe FilePath)  -- ^ output path of bindist, None for cross-  compileMakeBindist tver workdir ghcdir = do-    liftE $ configureBindist tver workdir ghcdir--    case mbuildConfig of-      Just bc -> liftIOException-        doesNotExistErrorType-        (FileDoesNotExistError bc)-        (liftIO $ copyFile bc (build_mk workdir) False)-      Nothing ->-        liftIO $ T.writeFile (build_mk workdir) (addBuildFlavourToConf defaultConf)--    liftE $ checkBuildConfig (build_mk workdir)--    lift $ logInfo $ "Building GHC version " <> tVerToText tver <> " (this may take a while)..."-    lEM $ make (maybe [] (\j -> ["-j" <> fS (show j)]) jobs) (Just workdir)--    if | isCross tver -> do-          lift $ logInfo "Installing cross toolchain..."-          tmpInstallDest <- lift withGHCupTmpDir-          lEM $ make ["DESTDIR=" <> fromGHCupPath tmpInstallDest, "install"] (Just workdir)-          liftE $ mergeGHCFileTree (tmpInstallDest `appendGHCupPath` dropDrive (fromInstallDir ghcdir)) ghcdir tver True-          pure Nothing-       | otherwise -> do-          lift $ logInfo "Creating bindist..."-          lEM $ make ["binary-dist"] (Just workdir)-          [tar] <- liftIO $ findFiles-            workdir-            (makeRegexOpts compExtended-                           execBlank-                           ([s|^ghc-.*\.tar\..*$|] :: ByteString)-            )-          liftE $ fmap Just $ copyBindist tver tar workdir--  build_mk workdir = workdir </> "mk" </> "build.mk"--  copyBindist :: ( MonadReader env m-                 , HasDirs env-                 , HasSettings env-                 , HasPlatformReq env-                 , MonadIO m-                 , MonadThrow m-                 , MonadCatch m-                 , HasLog env-                 )-              => GHCTargetVersion-              -> FilePath           -- ^ tar file-              -> FilePath           -- ^ workdir-              -> Excepts-                   '[CopyError]-                   m-                   FilePath-  copyBindist tver tar workdir = do-    Dirs {..} <- lift getDirs-    pfreq <- lift getPlatformReq-    c       <- liftIO $ BL.readFile (workdir </> tar)-    cDigest <--      fmap (T.take 8)-      . lift-      . throwEither-      . E.decodeUtf8'-      . B16.encode-      . SHA256.hashlazy-      $ c-    cTime <- liftIO getCurrentTime-    let tarName = makeValid ("ghc-"-                            <> T.unpack (tVerToText tver)-                            <> "-"-                            <> pfReqToString pfreq-                            <> "-"-                            <> iso8601Show cTime-                            <> "-"-                            <> T.unpack cDigest-                            <> ".tar"-                            <> takeExtension tar)-    let tarPath = fromGHCupPath cacheDir </> tarName-    copyFileE (workdir </> tar) tarPath False-    lift $ logInfo $ "Copied bindist to " <> T.pack tarPath-    pure tarPath--  checkBuildConfig :: (MonadReader env m, MonadCatch m, MonadIO m, HasLog env)-                   => FilePath-                   -> Excepts-                        '[FileDoesNotExistError, InvalidBuildConfig]-                        m-                        ()-  checkBuildConfig bc = do-    c <- liftIOException-           doesNotExistErrorType-           (FileDoesNotExistError bc)-           (liftIO $ B.readFile bc)-    let lines' = fmap T.strip . T.lines $ decUTF8Safe c--   -- for cross, we need Stage1Only-    case crossTarget of-      Just _ -> when ("Stage1Only = YES" `notElem` lines') $ throwE-        (InvalidBuildConfig-          [s|Cross compiling needs to be a Stage1 build, add "Stage1Only = YES" to your config!|]-        )-      _ -> pure ()--    forM_ buildFlavour $ \bf ->-      when (T.pack ("BuildFlavour = " <> bf) `notElem` lines') $ do-        lift $ logWarn $ "Customly specified build config overwrites --flavour=" <> T.pack bf <> " switch! Waiting 5 seconds..."-        liftIO $ threadDelay 5000000--  addBuildFlavourToConf bc = case buildFlavour of-    Just bf -> "BuildFlavour = " <> T.pack bf <> "\n" <> bc-    Nothing -> bc--  isCross :: GHCTargetVersion -> Bool-  isCross = isJust . _tvTarget---  configureBindist :: ( MonadReader env m-                      , HasDirs env-                      , HasSettings env-                      , HasPlatformReq env-                      , MonadThrow m-                      , MonadCatch m-                      , HasLog env-                      , MonadIO m-                      , MonadFail m-                      )-                   => GHCTargetVersion-                   -> FilePath-                   -> InstallDirResolved-                   -> Excepts-                        '[ FileDoesNotExistError-                         , InvalidBuildConfig-                         , PatchFailed-                         , ProcessError-                         , NotFoundInPATH-                         , CopyError-                         ]-                        m-                        ()-  configureBindist tver workdir (fromInstallDir -> ghcdir) = do-    PlatformRequest { .. } <- lift getPlatformReq-    lift $ logInfo [s|configuring build|]-    liftE $ configureWithGhcBoot (Just tver)-      (maybe mempty-                (\x -> ["--target=" <> T.unpack x])-                (_tvTarget tver)-      ++ ["--prefix=" <> ghcdir]-      ++ (if isWindows then ["--enable-tarballs-autodownload"] else [])-      -- https://github.com/haskell/ghcup-hs/issues/1032-      ++ ldOverride (_tvVersion tver) _rPlatform-      ++ fmap T.unpack aargs-      )-      (Just workdir)-      "ghc-conf"-    pure ()--  configureWithGhcBoot :: ( MonadReader env m-                          , HasSettings env-                          , HasDirs env-                          , HasLog env-                          , MonadIO m-                          , MonadThrow m)-                       => Maybe GHCTargetVersion-                       -> [String]         -- ^ args for configure-                       -> Maybe FilePath   -- ^ optionally chdir into this-                       -> FilePath         -- ^ log filename (opened in append mode)-                       -> Excepts '[ProcessError, NotFoundInPATH] m ()-  configureWithGhcBoot mtver args dir logf = do-    bghc <- liftE $ resolveGHC bstrap-    let execNew = execLogged-                    "sh"-                    ("./configure" : ("GHC=" <> bghc) : args)-                    dir-                    logf-                    Nothing-        execOld = execLogged-                   "sh"-                   ("./configure" : ("--with-ghc=" <> bghc) : args)-                   dir-                   logf-                   Nothing-    if | Just tver <- mtver-       , _tvVersion tver >= [vver|8.8.0|] -> lEM execNew-       | Nothing   <- mtver               -> lEM execNew -- need some default for git checkouts where we don't know yet-       | otherwise                        -> lEM execOld--  resolveGHC :: MonadIO m => Either Version FilePath -> Excepts '[NotFoundInPATH] m FilePath-  resolveGHC = \case-           Right g    -> pure g-           Left  bver -> do-             let ghc = "ghc-" <> (T.unpack . prettyVer $ bver) <> exeExt-             -- https://gitlab.haskell.org/ghc/ghc/-/issues/24682-             makeAbsolute ghc-----    --------------    --[ Other ]---    ------------------- | Creates @ghc-x.y.z@ and @ghc-x.y@ symlinks. This is used for--- both installing from source and bindist.-postGHCInstall :: ( MonadReader env m-                  , HasDirs env-                  , HasLog env-                  , MonadThrow m-                  , MonadFail m-                  , MonadIO m-                  , MonadCatch m-                  , MonadMask m-                  , MonadUnliftIO m-                  )-               => GHCTargetVersion-               -> Excepts '[NotInstalled] m ()-postGHCInstall ver@GHCTargetVersion {..} = do-  void $ liftE $ setGHC ver SetGHC_XYZ Nothing--  -- Create ghc-x.y symlinks. This may not be the current-  -- version, create it regardless.-  v' <--    handle (\(e :: ParseError) -> lift $ logWarn (T.pack $ displayException e) >> pure Nothing)-    $ fmap Just-    $ getMajorMinorV _tvVersion-  forM_ v' $ \(mj, mi) -> lift (getGHCForPVP (PVP (fromIntegral mj :| [fromIntegral mi])) _tvTarget)-    >>= mapM_ (\v -> liftE $ setGHC v SetGHC_XY Nothing)---ldOverride ::  Version -> Platform -> [String]-ldOverride ver plat-  | ver >= [vver|8.2.2|]-  = ["--disable-ld-override"]-  | otherwise-  = []--sanitizefGHCconfOptions :: MonadFail m => [String] -> m [String]-sanitizefGHCconfOptions args-  | "--prefix" `elem` fmap (takeWhile (/= '=')) args = fail "Don't explicitly set --prefix ...aborting"-  | otherwise = pure args-
− lib/GHCup/HLS.hs
@@ -1,744 +0,0 @@-{-# LANGUAGE CPP                   #-}-{-# LANGUAGE BangPatterns          #-}-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE FlexibleInstances     #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE QuasiQuotes           #-}--{-|-Module      : GHCup.HLS-Description : GHCup installation functions for HLS-Copyright   : (c) Julian Ospald, 2020-License     : LGPL-3.0-Maintainer  : hasufell@hasufell.de-Stability   : experimental-Portability : portable--}-module GHCup.HLS where--import           GHCup.Download-import           GHCup.Errors-import           GHCup.Types-import           GHCup.Types.JSON               ( )-import           GHCup.Types.Optics-import           GHCup.Utils-import           GHCup.Prelude-import           GHCup.Prelude.File-import           GHCup.Prelude.Logger-import           GHCup.Prelude.Process-import           GHCup.Prelude.String.QQ--import           Control.Applicative-import           Control.Exception.Safe-import           Control.Monad-#if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )-#endif-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-                                         hiding ( throwM )-import           Data.ByteString                ( ByteString )-import           Data.Either-import           Data.List-import           Data.Ord-import           Data.Maybe-import           Data.String                    ( fromString )-import           Data.Text                      ( Text )-import           Data.Versions                hiding ( patch )-import           Distribution.Types.Version   hiding ( Version )-import           Distribution.Types.PackageId-import           Distribution.Types.PackageDescription-import           Distribution.Types.GenericPackageDescription-import           Distribution.PackageDescription.Parsec-import           GHC.IO.Exception-import           Data.Variant.Excepts-import           Optics-import           Prelude                 hiding ( abs-                                                , writeFile-                                                )-import           Safe                    hiding ( at )-import           System.FilePath-import           System.IO.Error-import           Text.Regex.Posix-import           URI.ByteString--import qualified Data.List.NonEmpty            as NE-import qualified Data.ByteString               as B-import qualified Data.Text                     as T-import qualified Text.Megaparsec               as MP---data HLSVer = SourceDist Version-            | GitDist GitBranch-            | HackageDist Version-            | RemoteDist URI-            deriving (Eq, Show)----    ---------------------    --[ Installation ]---    ------------------------- | Like 'installHLSBin, except takes the 'DownloadInfo' as--- argument instead of looking it up from 'GHCupDownloads'.-installHLSBindist :: ( MonadMask m-                     , MonadCatch m-                     , MonadReader env m-                     , HasPlatformReq env-                     , HasDirs env-                     , HasSettings env-                     , HasLog env-                     , MonadResource m-                     , MonadIO m-                     , MonadUnliftIO m-                     , MonadFail m-                     )-                  => DownloadInfo-                  -> Version-                  -> InstallDir -- ^ isolated install path, if user passed any-                  -> Bool       -- ^ Force install-                  -> Excepts-                       '[ AlreadyInstalled-                        , CopyError-                        , DigestError-                        , ContentLengthError-                        , GPGError-                        , DownloadFailed-                        , NoDownload-                        , NotInstalled-                        , UnknownArchive-                        , TarDirDoesNotExist-                        , ArchiveResult-                        , FileAlreadyExistsError-                        , ProcessError-                        , DirNotEmpty-                        , UninstallFailed-                        , MergeFileTreeError-                        , URIParseError-                        ]-                       m-                       ()-installHLSBindist dlinfo ver installDir forceInstall = do-  lift $ logDebug $ "Requested to install hls version " <> prettyVer ver--  PlatformRequest {..} <- lift getPlatformReq-  Dirs {..} <- lift getDirs--  regularHLSInstalled <- lift $ hlsInstalled ver--  if-    | not forceInstall-    , regularHLSInstalled-    , GHCupInternal <- installDir -> do        -- regular install-        throwE $ AlreadyInstalled HLS ver--    | forceInstall-    , regularHLSInstalled-    , GHCupInternal <- installDir -> do        -- regular forced install-        lift $ logInfo "Removing the currently installed version of HLS before force installing!"-        liftE $ rmHLSVer ver--    | otherwise -> pure ()--  -- download (or use cached version)-  dl <- liftE $ downloadCached dlinfo Nothing--  -- unpack-  tmpUnpack <- lift withGHCupTmpDir-  liftE $ cleanUpOnError tmpUnpack (unpackToDir (fromGHCupPath tmpUnpack) dl)-  liftE $ catchWarn $ lEM @_ @'[ProcessError] $ darwinNotarization _rPlatform (fromGHCupPath tmpUnpack)--  -- the subdir of the archive where we do the work-  workdir <- fromGHCupPath <$> maybe (pure tmpUnpack) (liftE . intoSubdir tmpUnpack) (view dlSubdir dlinfo)-  legacy <- liftIO $ isLegacyHLSBindist workdir--  if-    | not forceInstall-    , not legacy-    , (IsolateDir fp) <- installDir -> liftE $ installDestSanityCheck (IsolateDirResolved fp)-    | otherwise -> pure ()--  case installDir of-    IsolateDir isoDir -> do-      lift $ logInfo $ "isolated installing HLS to " <> T.pack isoDir-      if legacy-      then liftE $ installHLSUnpackedLegacy workdir (IsolateDirResolved isoDir) ver forceInstall-      else liftE $ runBuildAction tmpUnpack $ installHLSUnpacked workdir (IsolateDirResolved isoDir) ver forceInstall--    GHCupInternal -> do-      if legacy-      then liftE $ installHLSUnpackedLegacy workdir (GHCupBinDir binDir) ver forceInstall-      else do-        inst <- ghcupHLSDir ver-        liftE $ runBuildAction tmpUnpack-              $ installHLSUnpacked workdir (GHCupDir inst) ver forceInstall-        liftE $ setHLS ver SetHLS_XYZ Nothing---isLegacyHLSBindist :: FilePath -- ^ Path to the unpacked hls bindist-                   -> IO Bool-isLegacyHLSBindist path = do-  not <$> doesFileExist (path </> "GNUmakefile")---- | Install an unpacked hls distribution.-installHLSUnpacked :: ( MonadMask m-                      , MonadUnliftIO m-                      , MonadReader env m-                      , MonadFail m-                      , HasLog env-                      , HasDirs env-                      , HasSettings env-                      , MonadCatch m-                      , MonadIO m-                      , MonadResource m-                      , HasPlatformReq env-                      )-                   => FilePath      -- ^ Path to the unpacked hls bindist (where the executable resides)-                   -> InstallDirResolved      -- ^ Path to install to-                   -> Version-                   -> Bool-                   -> Excepts '[ProcessError, CopyError, FileAlreadyExistsError, NotInstalled, MergeFileTreeError] m ()-installHLSUnpacked path inst ver forceInstall = do-  PlatformRequest { .. } <- lift getPlatformReq-  lift $ logInfo "Installing HLS"-  tmpInstallDest <- lift withGHCupTmpDir-  lEM $ make ["DESTDIR=" <> fromGHCupPath tmpInstallDest, "PREFIX=" <> fromInstallDir inst, "install"] (Just path)-  liftE $ catchWarn $ lEM @_ @'[ProcessError] $ darwinNotarization _rPlatform (fromGHCupPath tmpInstallDest)-  liftE $ mergeFileTree (tmpInstallDest `appendGHCupPath` dropDrive (fromInstallDir inst))-                   inst-                   HLS-                   (mkTVer ver)-                   (\f t -> liftIO $ do-                       mtime <- ifM (pathIsSymbolicLink f) (pure Nothing) (Just <$> getModificationTime f)-                       install f t (not forceInstall)-                       forM_ mtime $ setModificationTime t)---- | Install an unpacked hls distribution (legacy).-installHLSUnpackedLegacy :: (MonadReader env m, MonadFail m, HasLog env, MonadCatch m, MonadIO m)-                         => FilePath      -- ^ Path to the unpacked hls bindist (where the executable resides)-                         -> InstallDirResolved      -- ^ Path to install to-                         -> Version-                         -> Bool          -- ^ is it a force install-                         -> Excepts '[CopyError, FileAlreadyExistsError] m ()-installHLSUnpackedLegacy path installDir ver forceInstall = do-  lift $ logInfo "Installing HLS"-  liftIO $ createDirRecursive' (fromInstallDir installDir)--  -- install haskell-language-server-<ghcver>-  bins@(_:_) <- liftIO $ findFiles-    path-    (makeRegexOpts compExtended-                   execBlank-                   ([s|^haskell-language-server-[0-9].*$|] :: ByteString)-    )-  forM_ bins $ \f -> do-    let toF = dropSuffix exeExt f-              <> (case installDir of-                   IsolateDirResolved _ -> ""-                   _ -> ("~" <>) . T.unpack . prettyVer $ ver-                 )-              <> exeExt--    let srcPath = path </> f-    let destPath = fromInstallDir installDir </> toF--    -- destination could be an existing symlink-    -- for new make-based HLSes-    liftIO $ rmFileForce destPath--    copyFileE-      srcPath-      destPath-      (not forceInstall)-    lift $ chmod_755 destPath--  -- install haskell-language-server-wrapper-  let wrapper = "haskell-language-server-wrapper"-      toF = wrapper-            <> (case installDir of-                 IsolateDirResolved _ -> ""-                 _ -> ("-" <>) . T.unpack . prettyVer $ ver-               )-            <> exeExt-      srcWrapperPath = path </> wrapper <> exeExt-      destWrapperPath = fromInstallDir installDir </> toF--  liftIO $ rmFileForce destWrapperPath-  copyFileE-    srcWrapperPath-    destWrapperPath-    (not forceInstall)--  lift $ chmod_755 destWrapperPath------ | Installs hls binaries @haskell-language-server-\<ghcver\>@--- into @~\/.ghcup\/bin/@, as well as @haskell-languager-server-wrapper@.-installHLSBin :: ( MonadMask m-                 , MonadCatch m-                 , MonadReader env m-                 , HasPlatformReq env-                 , HasGHCupInfo env-                 , HasDirs env-                 , HasSettings env-                 , HasLog env-                 , MonadResource m-                 , MonadIO m-                 , MonadUnliftIO m-                 , MonadFail m-                 )-              => Version-              -> InstallDir-              -> Bool            -- force install-              -> Excepts-                   '[ AlreadyInstalled-                    , CopyError-                    , DigestError-                    , ContentLengthError-                    , GPGError-                    , DownloadFailed-                    , NoDownload-                    , NotInstalled-                    , UnknownArchive-                    , TarDirDoesNotExist-                    , ArchiveResult-                    , FileAlreadyExistsError-                    , ProcessError-                    , DirNotEmpty-                    , UninstallFailed-                    , MergeFileTreeError-                    , URIParseError-                    ]-                   m-                   ()-installHLSBin ver installDir forceInstall = do-  dlinfo <- liftE $ getDownloadInfo HLS ver-  installHLSBindist dlinfo ver installDir forceInstall---compileHLS :: ( MonadMask m-              , MonadCatch m-              , MonadReader env m-              , HasDirs env-              , HasSettings env-              , HasPlatformReq env-              , HasGHCupInfo env-              , HasLog env-              , MonadResource m-              , MonadIO m-              , MonadUnliftIO m-              , MonadFail m-              )-           => HLSVer-           -> [Version]-           -> Maybe Int-           -> Maybe [VersionPattern]-           -> InstallDir-           -> Maybe (Either FilePath URI)-           -> Maybe URI-           -> Bool-           -> Maybe (Either FilePath [URI])  -- ^ patches-           -> [Text]                   -- ^ additional args to cabal install-           -> Excepts '[ NoDownload-                       , GPGError-                       , DownloadFailed-                       , DigestError-                       , ContentLengthError-                       , UnknownArchive-                       , TarDirDoesNotExist-                       , ArchiveResult-                       , BuildFailed-                       , NotInstalled-                       , URIParseError-                       ] m Version-compileHLS targetHLS ghcs jobs vps installDir cabalProject cabalProjectLocal updateCabal patches cabalArgs = do-  pfreq@PlatformRequest { .. } <- lift getPlatformReq-  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-  Dirs { .. } <- lift getDirs--  when updateCabal $ reThrowAll @_ @'[ProcessError] DownloadFailed $ do-    lift $ logInfo "Updating cabal DB"-    lEM $ exec "cabal" ["update"] (Just $ fromGHCupPath tmpDir) Nothing--  (workdir, tmpUnpack, tver, ov) <- case targetHLS of-    -- unpack from version tarball-    SourceDist tver -> do-      lift $ logDebug $ "Requested to compile: " <> prettyVer tver--      -- download source tarball-      dlInfo <--        preview (ix HLS % ix (mkTVer tver) % viSourceDL % _Just) dls-          ?? NoDownload (mkTVer tver) HLS (Just pfreq)-      dl <- liftE $ downloadCached dlInfo Nothing--      -- unpack-      tmpUnpack <- lift mkGhcupTmpDir-      liftE $ cleanUpOnError tmpUnpack (unpackToDir (fromGHCupPath tmpUnpack) dl)-      liftE $ catchWarn $ lEM @_ @'[ProcessError] $ darwinNotarization _rPlatform (fromGHCupPath tmpUnpack)--      workdir <- maybe (pure tmpUnpack)-                       (liftE . intoSubdir tmpUnpack)-                       (view dlSubdir dlInfo)--      ov <- case vps of-              Just vps' -> fmap Just $ expandVersionPattern (Just tver) "" "" "" "" vps'-              Nothing   -> pure Nothing--      pure (workdir, tmpUnpack, tver, ov)--    HackageDist tver -> do-      lift $ logDebug $ "Requested to compile (from hackage): " <> prettyVer tver--      -- download source tarball-      tmpUnpack <- lift mkGhcupTmpDir-      let hls = "haskell-language-server-" <> T.unpack (prettyVer tver)-      reThrowAll @_ @'[ProcessError] DownloadFailed $ do-        -- unpack-        lEM $ exec "cabal" ["unpack", hls] (Just $ fromGHCupPath tmpUnpack) Nothing--      let workdir = appendGHCupPath tmpUnpack hls--      ov <- case vps of-              Just vps' -> fmap Just $ expandVersionPattern (Just tver) "" "" "" "" vps'-              Nothing   -> pure Nothing--      pure (workdir, tmpUnpack, tver, ov)--    RemoteDist uri -> do-      lift $ logDebug $ "Requested to compile (from uri): " <> T.pack (show uri)--      -- download source tarball-      tmpDownload <- lift withGHCupTmpDir-      tmpUnpack <- lift mkGhcupTmpDir-      tar <- liftE $ download uri Nothing Nothing Nothing (fromGHCupPath tmpDownload) Nothing False-      (cf, tver) <- liftE $ cleanUpOnError tmpUnpack $ do-        unpackToDir (fromGHCupPath tmpUnpack) tar-        let regex = [s|^(.*/)*haskell-language-server\.cabal$|] :: B.ByteString-        [cabalFile] <- liftIO $ findFilesDeep-          tmpUnpack-          (makeRegexOpts compExtended-                         execBlank-                         regex-          )-        tver <- getCabalVersion (fromGHCupPath tmpUnpack </> cabalFile)-        pure (cabalFile, tver)--      let workdir = appendGHCupPath tmpUnpack (takeDirectory cf)--      ov <- case vps of-              Just vps' -> fmap Just $ expandVersionPattern (Just tver) "" "" "" "" vps'-              Nothing   -> pure Nothing--      pure (workdir, tmpUnpack, tver, ov)--    -- clone from git-    GitDist GitBranch{..} -> do-      tmpUnpack <- lift mkGhcupTmpDir-      let git args = execLogged "git" ("--no-pager":args) (Just $ fromGHCupPath tmpUnpack) "git" Nothing-      cleanUpOnError tmpUnpack $ reThrowAll @_ @'[ProcessError] DownloadFailed $ do-        let rep = fromMaybe "https://github.com/haskell/haskell-language-server.git" repo-        lift $ logInfo $ "Fetching git repo " <> T.pack rep <> " at ref " <> T.pack ref <> " (this may take a while)"-        lEM $ git [ "init" ]-        lEM $ git [ "remote"-                  , "add"-                  , "origin"-                  , fromString rep ]--        -- figure out if we can do a shallow clone-        remoteBranches <- catchE @ProcessError @'[ProcessError] @'[] (\_ -> pure [])-            $ fmap processBranches $ gitOut ["ls-remote", "--heads", "origin"] (fromGHCupPath tmpUnpack)-        let shallow_clone-              | gitDescribeRequested                 = False-              | isCommitHash ref                     = True-              | fromString ref `elem` remoteBranches = True-              | otherwise                            = False--        lift $ logDebug $ "Shallow clone: " <> T.pack (show shallow_clone)--        -- fetch-        let fetch_args-              | shallow_clone = ["fetch", "--depth", "1", "--quiet", "origin", fromString ref]-              | otherwise     = ["fetch", "--tags",       "--quiet", "origin"                ]-        lEM $ git fetch_args--        -- checkout-        lEM $ git [ "checkout", fromString ref ]--        -- gather some info-        git_describe <- if shallow_clone-                        then pure Nothing-                        else fmap Just $ gitOut ["describe", "--tags"] (fromGHCupPath tmpUnpack)-        chash <- gitOut ["rev-parse", "HEAD" ] (fromGHCupPath tmpUnpack)-        branch <- gitOut ["rev-parse", "--abbrev-ref", "HEAD" ] (fromGHCupPath tmpUnpack)-        tver <- getCabalVersion (fromGHCupPath tmpUnpack </> "haskell-language-server.cabal")--        liftE $ catchWarn $ lEM @_ @'[ProcessError] $ darwinNotarization _rPlatform (fromGHCupPath tmpUnpack)--        ov <- case vps of-                Just vps' -> fmap Just $ expandVersionPattern-                                           (Just tver)-                                           (take 7 $ T.unpack chash)-                                           (T.unpack chash)-                                           (maybe "" T.unpack git_describe)-                                           (T.unpack branch)-                                           vps'-                Nothing -> pure Nothing--        lift $ logInfo $ "Examining git ref " <> T.pack ref <> "\n  " <>-                                    "HLS version (from cabal file): " <> prettyVer tver <>-                                    "\n  branch: " <> branch <>-                                    (if not shallow_clone then "\n  " <> "'git describe' output: " <> fromJust git_describe else mempty) <>-                                    (if isCommitHash ref then mempty else "\n  " <> "commit hash: " <> chash)-        pure (tmpUnpack, tmpUnpack, tver, ov)--  -- the version that's installed may differ from the-  -- compiled version, so the user can overwrite it-  installVer <- maybe (pure tver) pure ov--  liftE $ runBuildAction-    tmpUnpack-    (reThrowAll @_ @'[GPGError, DownloadFailed, DigestError, ContentLengthError, PatchFailed, ProcessError, FileAlreadyExistsError, CopyError] @'[BuildFailed] (BuildFailed $ fromGHCupPath workdir) $ do-      let tmpInstallDir = fromGHCupPath workdir </> "out"-      liftIO $ createDirRecursive' tmpInstallDir--      -- apply patches-      liftE $ applyAnyPatch patches (fromGHCupPath workdir)--      -- set up project files-      cp <- case cabalProject of-        Just (Left cp)-          | isAbsolute cp -> do-              copyFileE cp (fromGHCupPath workdir </> "cabal.project") False-              pure "cabal.project"-          | otherwise -> pure (takeFileName cp)-        Just (Right uri) -> do-          tmpUnpack' <- lift withGHCupTmpDir-          cp <- liftE $ download uri Nothing Nothing Nothing (fromGHCupPath tmpUnpack') (Just "cabal.project") False-          copyFileE cp (fromGHCupPath workdir </> "cabal.project") False-          pure "cabal.project"-        Nothing-          | HackageDist _ <- targetHLS -> do-              liftIO $ B.writeFile (fromGHCupPath workdir </> "cabal.project") "packages: ./"-              pure "cabal.project"-          | RemoteDist _ <- targetHLS -> do-              let cabalFile = fromGHCupPath workdir </> "cabal.project"-              liftIO $ whenM (not <$> doesFileExist cabalFile) $ B.writeFile cabalFile "packages: ./"-              pure "cabal.project"-          | otherwise -> pure "cabal.project"-      forM_ cabalProjectLocal $ \uri -> do-        tmpUnpack' <- lift withGHCupTmpDir-        cpl <- liftE $ download uri Nothing Nothing Nothing (fromGHCupPath tmpUnpack') (Just (cp <.> "local")) False-        copyFileE cpl (fromGHCupPath workdir </> cp <.> "local") False-      artifacts <- forM (sort ghcs) $ \ghc -> do-        let ghcInstallDir = tmpInstallDir </> T.unpack (prettyVer ghc)-        liftIO $ createDirRecursive' tmpInstallDir-        lift $ logInfo $ "Building HLS " <> prettyVer installVer <> " for GHC version " <> prettyVer ghc-        liftE $ lEM @_ @'[ProcessError] $-          execLogged "cabal" ( [ "v2-install"-                               , "-w"-                               , "ghc-" <> T.unpack (prettyVer ghc)-                               , "--install-method=copy"-                               ] ++-                               maybe [] (\j -> ["--jobs=" <> show j]) jobs ++-                               [ "--overwrite-policy=always"-                               , "--disable-profiling"-                               , "--disable-tests"-                               , "--installdir=" <> ghcInstallDir-                               , "--project-file=" <> cp-                               ] ++ fmap T.unpack cabalArgs ++ [-                                 "exe:haskell-language-server"-                               , "exe:haskell-language-server-wrapper"]-                             )-                             (Just $ fromGHCupPath workdir)-                             "cabal"-                             Nothing-        pure ghcInstallDir--      forM_ artifacts $ \artifact -> do-        logDebug $ T.pack (show artifact)-        liftIO $ renameFile (artifact </> "haskell-language-server" <.> exeExt)-          (tmpInstallDir </> "haskell-language-server-" <> takeFileName artifact <.> exeExt)-        liftIO $ renameFile (artifact </> "haskell-language-server-wrapper" <.> exeExt)-          (tmpInstallDir </> "haskell-language-server-wrapper" <.> exeExt)--      case installDir of-        IsolateDir isoDir -> do-          lift $ logInfo $ "isolated installing HLS to " <> T.pack isoDir-          liftE $ installHLSUnpackedLegacy tmpInstallDir (IsolateDirResolved isoDir) installVer True-        GHCupInternal -> do-          liftE $ installHLSUnpackedLegacy tmpInstallDir (GHCupBinDir binDir) installVer True-    )--  pure installVer- where-  gitDescribeRequested = maybe False (GitDescribe `elem`) vps---    ------------------    --[ Set/Unset ]---    --------------------- | Set the haskell-language-server symlinks.-setHLS :: ( MonadReader env m-          , HasDirs env-          , HasLog env-          , MonadIO m-          , MonadMask m-          , MonadFail m-          , MonadUnliftIO m-          )-       => Version-       -> SetHLS-       -> Maybe FilePath  -- if set, signals that we're not operating in ~/.ghcup/bin-                          -- and don't want mess with other versions-       -> Excepts '[NotInstalled] m ()-setHLS ver shls mBinDir = do-  whenM (lift $ not <$> hlsInstalled ver) (throwE (NotInstalled HLS (GHCTargetVersion Nothing ver)))--  -- symlink destination-  binDir <- case mBinDir of-    Just x -> pure x-    Nothing -> do-      Dirs {binDir = f} <- lift getDirs-      pure f--  -- first delete the old symlinks-  when (isNothing mBinDir) $-    case shls of-      -- not for legacy-      SetHLS_XYZ -> liftE $ rmMinorHLSSymlinks ver-      -- legacy and new-      SetHLSOnly -> liftE rmPlainHLS--  case shls of-    -- not for legacy-    SetHLS_XYZ -> do-      bins <- lift $ hlsInternalServerScripts ver Nothing--      forM_ bins $ \f -> do-        let fname = takeFileName f-        destL <- binarySymLinkDestination binDir f-        let target = if "haskell-language-server-wrapper" `isPrefixOf` fname-                     then fname <> "-" <> T.unpack (prettyVer ver) <> exeExt-                     else fname <> "~" <> T.unpack (prettyVer ver) <> exeExt-        lift $ createLink destL (binDir </> target)--    -- legacy and new-    SetHLSOnly -> do-      -- set haskell-language-server-<ghcver> symlinks-      bins <- lift $ hlsServerBinaries ver Nothing-      when (null bins) $ throwE $ NotInstalled HLS (GHCTargetVersion Nothing ver)--      forM_ bins $ \f -> do-        let destL = f-        let target = (<> exeExt) . head . splitOn "~" $ f-        lift $ createLink destL (binDir </> target)--      -- set haskell-language-server-wrapper symlink-      let destL = "haskell-language-server-wrapper-" <> T.unpack (prettyVer ver) <> exeExt-      let wrapper = binDir </> "haskell-language-server-wrapper" <> exeExt--      lift $ createLink destL wrapper--      when (isNothing mBinDir) $-        lift warnAboutHlsCompatibility--      liftIO (isShadowed wrapper) >>= \case-        Nothing -> pure ()-        Just pa -> lift $ logWarn $ T.pack $ prettyHFError (ToolShadowed HLS pa wrapper ver)---unsetHLS :: ( MonadMask m-            , MonadReader env m-            , HasDirs env-            , MonadIO m)-         => m ()-unsetHLS = do-  Dirs {..} <- getDirs-  let wrapper = binDir </> "haskell-language-server-wrapper" <> exeExt-  bins   <- liftIO $ handleIO (\_ -> pure []) $ findFiles'-    binDir-    (MP.chunk "haskell-language-server-" <* pvp' <* MP.chunk (T.pack exeExt) <* MP.eof)-  forM_ bins (hideError doesNotExistErrorType . rmLink . (binDir </>))-  hideError doesNotExistErrorType $ rmLink wrapper-----    ----------------    --[ Removal ]---    -------------------- | Delete a hls version. Will try to fix the hls symlinks--- after removal (e.g. setting it to an older version).-rmHLSVer :: ( MonadMask m-            , MonadReader env m-            , HasDirs env-            , MonadThrow m-            , HasLog env-            , MonadIO m-            , MonadFail m-            , MonadCatch m-            , MonadUnliftIO m-            )-         => Version-         -> Excepts '[NotInstalled, UninstallFailed] m ()-rmHLSVer ver = do-  whenM (lift $ fmap not $ hlsInstalled ver) $ throwE (NotInstalled HLS (GHCTargetVersion Nothing ver))--  isHlsSet <- lift hlsSet--  liftE $ rmMinorHLSSymlinks ver--  when (Just ver == isHlsSet) $ do-    -- delete all set symlinks-    liftE rmPlainHLS--  hlsDir' <- ghcupHLSDir ver-  let hlsDir = fromGHCupPath hlsDir'-  lift (getInstalledFiles HLS (mkTVer ver)) >>= \case-    Just files -> do-      lift $ logInfo $ "Removing files safely from: " <> T.pack hlsDir-      forM_ files (lift . hideError NoSuchThing . recycleFile . (\f -> hlsDir </> dropDrive f))-      removeEmptyDirsRecursive hlsDir-      survivors <- liftIO $ hideErrorDef [doesNotExistErrorType] [] $ listDirectory hlsDir-      f <- recordedInstallationFile HLS (mkTVer ver)-      lift $ recycleFile f-      when (not (null survivors)) $ throwE $ UninstallFailed hlsDir survivors-    Nothing -> do-      isDir <- liftIO $ doesDirectoryExist hlsDir-      isSyml <- liftIO $ handleIO (\_ -> pure False) $ pathIsSymbolicLink hlsDir-      when (isDir && not isSyml) $ do-        lift $ logInfo $ "Removing legacy directory recursively: " <> T.pack hlsDir-        recyclePathForcibly hlsDir'--  when (Just ver == isHlsSet) $ do-    -- set latest hls-    hlsVers <- lift $ fmap rights getInstalledHLSs-    case headMay . sortBy (comparing Down) $ hlsVers of-      Just latestver -> liftE $ setHLS latestver SetHLSOnly Nothing-      Nothing        -> pure ()---getCabalVersion :: (MonadIO m, MonadFail m) => FilePath -> m Version-getCabalVersion fp = do-  contents <- liftIO $ B.readFile fp-  gpd <- case parseGenericPackageDescriptionMaybe contents of-           Nothing -> fail $ "could not parse cabal file: " <> fp-           Just r -> pure r-  let tver = (\c -> Version Nothing c Nothing Nothing)-           . Chunks-           . NE.fromList-           . fmap (Numeric . fromIntegral)-           . versionNumbers-           . pkgVersion-           . package-           . packageDescription-           $ gpd-  pure tver
+ lib/GHCup/Hardcoded/URLs.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE QuasiQuotes #-}++{-|+Module      : GHCup.Hardcoded.URLs+Description : URLs used by GHCup at runtime+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Hardcoded.URLs where++import GHCup.Types++import URI.ByteString+import URI.ByteString.QQ++import qualified Data.Text              as T++-- | This reflects the API version of the YAML.+--+-- Note that when updating this, CI requires that the file exists AND the same file exists at+-- 'https://www.haskell.org/ghcup/exp/ghcup-<ver>.yaml' with some newlines added.+-- TODO: revert to master+ghcupURL :: URI+ghcupURL = [uri|https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-0.1.0.yaml|]++stackSetupURL :: URI+stackSetupURL = [uri|https://raw.githubusercontent.com/commercialhaskell/stackage-content/master/stack/stack-setup-2.yaml|]++shimGenURL :: URI+shimGenURL = [uri|https://downloads.haskell.org/~ghcup/shimgen/shim-2.exe|]++shimGenSHA :: T.Text+shimGenSHA = T.pack "7c55e201f71860c5babea886007c8fa44b861abf50d1c07e5677eb0bda387a70"++channelURL :: ChannelAlias -> URI+channelURL = \case+  DefaultChannel -> ghcupURL+  StackChannel -> stackSetupURL+  CrossChannel -> [uri|https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-cross-0.1.0.yaml|]+  PrereleasesChannel -> [uri|https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.1.0.yaml|]+  VanillaChannel -> [uri|https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-vanilla-0.1.0.yaml|]+  ThirdPartyChannel -> [uri|https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-3rdparty-0.1.0.yaml|]+
+ lib/GHCup/Hardcoded/Version.hs view
@@ -0,0 +1,34 @@+{-|+Module      : GHCup.Hardcoded.Version+Description : Version information+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Hardcoded.Version where++import GHCup.Prelude.Version+import GHCup.Types+import Paths_ghcup           ( version )++import Data.Maybe        ( fromJust )+import Data.Version      ( Version (versionBranch) )++import qualified Data.List.NonEmpty     as NE+import qualified Data.Text              as T+import qualified Data.Versions          as V+++-- | The current ghcup version.+ghcUpVer :: V.PVP+ghcUpVer = V.PVP . NE.fromList . fmap fromIntegral $ versionBranch version++ghcUpVer' :: TargetVersion+ghcUpVer' = mkTVer $ fromJust $ pvpToVersion ghcUpVer mempty++-- | ghcup version as numeric string.+numericVer :: String+numericVer = T.unpack . V.prettyPVP $ ghcUpVer+
+ lib/GHCup/Input/Parsers.hs view
@@ -0,0 +1,507 @@+{-# OPTIONS_GHC -Wno-orphans #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ViewPatterns #-}++module GHCup.Input.Parsers where+++import GHCup.Command.List+import GHCup.Errors+import GHCup.Prelude+import GHCup.Prelude.Attoparsec as AP+import GHCup.Prelude.MegaParsec as MP+import GHCup.Query.DB+import GHCup.Query.Metadata+import GHCup.Types+import GHCup.Types.Optics+import GHCup.Input.Parsers.URI+import GHCup.Types.JSON++import Control.Applicative    ( Alternative (..), (<|>) )+import Control.Monad          ( forM, when )+#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Monad.Reader+import Data.Aeson+import Data.Bifunctor+import Data.Char            as C+import Data.Either+import Data.Functor+import Data.List            ( sort )+import Data.Maybe+import Data.Text            ( Text )+import Data.Time.Calendar   ( Day )+import Data.Time.Format     ( defaultTimeLocale, parseTimeM )+import Data.Variant.Excepts+import Data.Versions+import Data.Void+import Optics               hiding ( set )+import Prelude              hiding ( appendFile )+import Safe+import System.FilePath+import URI.ByteString       hiding ( parseURI )+import Text.PrettyPrint.HughesPJClass (prettyShow)++import qualified Data.Attoparsec.ByteString as AP+import qualified Data.ByteString.UTF8       as UTF8+import qualified Data.Text                  as T+import qualified Data.Text.Lazy             as LT+import qualified Data.Text.Lazy.Encoding    as LE+import qualified Text.Megaparsec            as MP+#if !MIN_VERSION_aeson(2,0,0)+import qualified Data.HashMap.Strict as KM+#endif++-- $setup+-- >>> :set -XOverloadedStrings+-- >>> :set -XDataKinds+-- >>> :set -XTypeApplications+-- >>> :set -XQuasiQuotes+-- >>> import System.Directory+-- >>> import URI.ByteString+-- >>> import qualified Data.Text as T+-- >>> import GHCup.Prelude+-- >>> import GHCup.Download+-- >>> import GHCup.Version+-- >>> import GHCup.Errors+-- >>> import GHCup.Types+-- >>> import GHCup.Query.GHCupDirs+-- >>> import GHCup.Types.Optics+-- >>> import Data.Versions+-- >>> import Optics+-- >>> import GHCup.Prelude.Version.QQ+-- >>> import qualified Data.Text.Encoding as E+-- >>> import qualified Data.Map.Strict               as M+-- >>> import Control.Monad.Reader+-- >>> import Data.Variant.Excepts+-- >>> import Text.PrettyPrint.HughesPJClass ( prettyShow )+-- >>> let lc = LoggerConfig { lcPrintDebug = False, consoleOutter = mempty, fileOutter = mempty, fancyColors = False }+-- >>> dirs' <- getAllDirs+-- >>> let installedVersions = [ ([pver|8.10.7|], "-debug+lol", Nothing), ([pver|8.10.4|], "", Nothing), ([pver|8.8.4|], "", Nothing), ([pver|8.8.3|], "", Nothing) ]+-- >>> let settings = defaultSettings { cache = True, metaCache = 0, noNetwork = True }+-- >>> let leanAppState = LeanAppState settings dirs' defaultKeyBindings lc+-- >>> cwd <- getCurrentDirectory+-- >>> (Right ref) <- pure $ GHCup.Utils.parseURI $ "file://" <> E.encodeUtf8 (T.pack cwd) <> "/data/metadata/" <> (urlBaseName . view pathL' $ ghcupURL)+-- >>> (Right ref') <- pure $ GHCup.Utils.parseURI $ "file://" <> E.encodeUtf8 (T.pack cwd) <> "/data/metadata/" <> (urlBaseName . view pathL' $ channelURL PrereleasesChannel)+-- >>> (VRight r) <- (fmap . fmap) _ghcupDownloads $ flip runReaderT leanAppState . runE @'[DigestError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError, ContentLengthError] $ liftE (getBase ref) >>= liftE . decodeMetadata @GHCupInfo+-- >>> (VRight r') <- (fmap . fmap) _ghcupDownloads $ flip runReaderT leanAppState . runE @'[DigestError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError, ContentLengthError] $ liftE (getBase ref') >>= liftE . decodeMetadata @GHCupInfo+-- >>> let rr = M.unionsWith (M.unionWith (\_ b2 -> b2)) [r, r']+-- >>> let go = flip runReaderT leanAppState . fmap (tVerToText . fst)+++    -------------+    --[ Types ]--+    -------------++-- a superset of ToolVersion+data SetToolVersion+  = SetGHCVersion TargetVersionReq+  | SetToolVersion VersionReq+  | SetToolTag Tag+  | SetToolDay Day+  | SetRecommended+  | SetNext+  deriving (Eq, Show)++prettyToolVer :: ToolVersion -> String+prettyToolVer (GHCVersion v')  = prettyShow v'+prettyToolVer (ToolVersion v') = prettyShow v'+prettyToolVer (ToolTag t)      = show t+prettyToolVer (ToolDay day)    = show day++toSetToolVer :: Maybe ToolVersion -> SetToolVersion+toSetToolVer (Just (GHCVersion v'))  = SetGHCVersion v'+toSetToolVer (Just (ToolVersion v')) = SetToolVersion v'+toSetToolVer (Just (ToolTag t'))     = SetToolTag t'+toSetToolVer (Just (ToolDay d'))     = SetToolDay d'+toSetToolVer Nothing                 = SetRecommended+++platformParser :: String -> Either String PlatformRequest+platformParser s' = case MP.parse (platformP <* MP.eof) "" (T.pack s') of+  Right r -> pure r+  Left  e -> Left $ errorBundlePretty e+ where+  archP :: MP.Parsec Void Text Architecture+  archP = choice' ((\x -> MP.chunk (T.pack $ archToString x) $> x) <$> ([minBound..maxBound] :: [Architecture]))+  platformP :: MP.Parsec Void Text PlatformRequest+  platformP = choice'+    [ (`PlatformRequest` FreeBSD)+    <$> (archP <* MP.chunk "-")+    <*> (  MP.chunk "portbld"+        *> (   MP.try (Just <$> verP (MP.chunk "-freebsd" <* MP.eof))+           <|> pure Nothing+           )+        <* MP.chunk "-freebsd"+        )+    , (`PlatformRequest` Darwin)+    <$> (archP <* MP.chunk "-")+    <*> (  MP.chunk "apple"+        *> (   MP.try (Just <$> verP (MP.chunk "-darwin" <* MP.eof))+           <|> pure Nothing+           )+        <* MP.chunk "-darwin"+        )+    , (\a d mv -> PlatformRequest a (Linux d) mv)+    <$> (archP <* MP.chunk "-")+    <*> distroP+    <*> ((MP.try (Just <$> verP (MP.chunk "-linux" <* MP.eof)) <|> pure Nothing+         )+        <* MP.chunk "-linux"+        )+    , (\a -> PlatformRequest a Windows Nothing)+    <$> ((archP <* MP.chunk "-")+        <* (MP.chunk "unknown-mingw32" <|> MP.chunk "unknown-windows" <|> MP.chunk "windows"))+    ]+  distroP :: MP.Parsec Void Text LinuxDistro+  distroP = choice' ((\d -> MP.chunk (T.pack $ distroToString d) $> d) <$> allDistros)+++uriParser :: String -> Either String URI+uriParser = first show . parseURI . UTF8.fromString++filePathParser :: FilePath -> Either String FilePath+filePathParser f =+  if isValid f+  then Right $ normalise f+  else Left "Please enter a valid filepath."++absolutePathParser :: FilePath -> Either String FilePath+absolutePathParser f =+  if isValid f && isAbsolute f+  then Right $ normalise f+  else Left "Please enter a valid absolute filepath."++isolateParser :: FilePath -> Either String FilePath+isolateParser f =+  if isValid f && isAbsolute f+  then Right $ normalise f+  else Left "Please enter a valid filepath for isolate dir."++toolParser :: String -> Either String Tool+toolParser s' = case fmap toLower s' of+                  "ghcup" -> Left "'ghcup' is not a valid tool in this context"+                  s''     -> Right $ Tool s''++toolParserWithGHCup :: String -> Either String Tool+toolParserWithGHCup s' = case fmap toLower s' of+                           s'' -> Right $ Tool s''++installTargetParser :: String -> Either String [String]+installTargetParser = Right . words++toolAndVersionParser :: String -> Either String (Tool, ToolVersion)+toolAndVersionParser (T.pack -> s') = do+  let (tool, toolVersion) = T.breakOn "," s'+  when (toolVersion == "") $ Left "Missing tool version"+  t <- toolParser (T.unpack tool)+  v <- toolVersionTagEither (tail $ T.unpack toolVersion)+  pure (t, v)++-- this accepts cross prefix+ghcVersionTagEither :: String -> Either String ToolVersion+ghcVersionTagEither s' =+  second ToolDay (dayParser s') <|> second ToolTag (tagEither s') <|> second GHCVersion (ghcVersionEither' s')++-- this ignores cross prefix+toolVersionTagEither :: String -> Either String ToolVersion+toolVersionTagEither s' =+  second ToolDay (dayParser s') <|> second ToolTag (tagEither s') <|> second ToolVersion (toolVersionEither' s')++tagEither :: String -> Either String Tag+tagEither s' = case fmap toLower s' of+  "recommended"              -> Right Recommended+  "latest"                   -> Right Latest+  "latest-prerelease"        -> Right LatestPrerelease+  "latest-nightly"           -> Right LatestNightly+  ('b':'a':'s':'e':'-':ver') -> case pvp (T.pack ver') of+                                  Right x -> Right (Base x)+                                  Left  _ -> Left $ "Invalid PVP version for base " <> ver'+  other                      -> Left $ "Unknown tag " <> other+++ghcVersionEither :: String -> Either String TargetVersion+ghcVersionEither str' = do+  v <- first (const "Not a valid version") . MP.parse ghcTargetVerP "" . T.pack $ str'+  if safeVersion v+  then pure v+  else Left "Unsafe version, try something more vanilla like '1.2.3'"++toolVersionEither :: String -> Either String Version+toolVersionEither str' = do+  v <- first (const "Not a valid version") . MP.parse (version' <* MP.eof) "" . T.pack $ str'+  if safeVersion (mkTVer v)+  then pure v+  else Left "Unsafe version, try something more vanilla like '1.2.3'"++ghcVersionEither' :: String -> Either String TargetVersionReq+ghcVersionEither' str' = do+  treq <- first (const "Not a valid version") . MP.parse ghcTargetVerRevP "" . T.pack $ str'+  if safeVersion (_tvqTargetVer treq)+  then pure treq+  else Left "Unsafe version, try something more vanilla like '1.2.3'"++toolVersionEither' :: String -> Either String VersionReq+toolVersionEither' str' = do+  vreq <- first (const "Not a valid version") . MP.parse (verRevP <* MP.eof) "" . T.pack $ str'+  if safeVersion (mkTVer $ _vqVersion vreq)+  then pure vreq+  else Left "Unsafe version, try something more vanilla like '1.2.3'"+++dayParser :: String -> Either String Day+dayParser s = maybe (Left $ "Could not parse \"" <> s <> "\". Expected format is: YYYY-MM-DD") Right+            $ parseTimeM True defaultTimeLocale "%Y-%-m-%-d" s++revisionShowParser :: String -> Either String ShowRevisions+revisionShowParser s' | t == T.pack "updates"   = Right ShowUpdates+                      | t == T.pack "all"       = Right ShowAll+                      | t == T.pack "none"      = Right ShowNone+                      | otherwise               = Left ("Unknown criteria: " <> s')+  where t = T.toLower (T.pack s')++criteriaParser :: String -> Either String ListCriteria+criteriaParser s' | t == T.pack "installed"   = Right $ ListInstalled True+                  | t == T.pack "set"         = Right $ ListSet True+                  | t == T.pack "available"   = Right $ ListAvailable True+                  | t == T.pack "+installed"  = Right $ ListInstalled True+                  | t == T.pack "+set"        = Right $ ListSet True+                  | t == T.pack "+available"  = Right $ ListAvailable True+                  | t == T.pack "-installed"  = Right $ ListInstalled False+                  | t == T.pack "-set"        = Right $ ListSet False+                  | t == T.pack "-available"  = Right $ ListAvailable False+                  | otherwise                 = Left ("Unknown criteria: " <> s')+  where t = T.toLower (T.pack s')++++keepOnParser :: String -> Either String KeepDirs+keepOnParser s' | t == T.pack "always" = Right Always+                | t == T.pack "errors" = Right Errors+                | t == T.pack "never"  = Right Never+                | otherwise            = Left ("Unknown keep value: " <> s')+  where t = T.toLower (T.pack s')+++downloaderParser :: String -> Either String Downloader+downloaderParser s' | t == T.pack "curl"     = Right Curl+                    | t == T.pack "wget"     = Right Wget+#if defined(INTERNAL_DOWNLOADER)+                    | t == T.pack "internal" = Right Internal+#endif+                    | otherwise = Left ("Unknown downloader value: " <> s')+  where t = T.toLower (T.pack s')++gpgParser :: String -> Either String GPGSetting+gpgParser s' | t == T.pack "strict" = Right GPGStrict+             | t == T.pack "lax"    = Right GPGLax+             | t == T.pack "none"   = Right GPGNone+             | otherwise = Left ("Unknown gpg setting value: " <> s')+  where t = T.toLower (T.pack s')++++overWriteVersionParser :: String -> Either String [VersionPattern]+overWriteVersionParser = first (const "Not a valid version pattern") . MP.parse (MP.many versionPattern <* MP.eof) "" . T.pack+ where+  versionPattern :: MP.Parsec Void Text VersionPattern+  versionPattern = do+    str' <- T.unpack <$> MP.takeWhileP Nothing (/= '%')+    if str' /= mempty+    then pure (S str')+    else     fmap (const CabalVer)      v_cabal+         <|> fmap (const GitBranchName) b_name+         <|> fmap (const GitHashShort)  s_hash+         <|> fmap (const GitHashLong)   l_hash+         <|> fmap (const GitDescribe)   g_desc+         <|> ((\a b -> S (a : T.unpack b)) <$> MP.satisfy (const True) <*> MP.takeWhileP Nothing (== '%')) -- invalid pattern, e.g. "%k"+   where+    v_cabal = MP.chunk "%v"+    b_name  = MP.chunk "%b"+    s_hash  = MP.chunk "%h"+    l_hash  = MP.chunk "%H"+    g_desc  = MP.chunk "%g"++    -----------------+    --[ Utilities ]--+    -----------------+++resolveVersion ::+  ( HasLog env+  , MonadFail m+  , MonadReader env m+  , HasGHCupInfo env+  , HasDirs env+  , MonadIOish m+  )+  => Maybe ToolVersion+  -> GuessMode+  -> Tool+  -> Excepts+       '[ TagNotFound+        , DayNotFound+        , NextVerNotFound+        , NoToolVersionSet+        , ParseError+        ] m TargetVersionReq+resolveVersion tv = resolveVersion' (toSetToolVer tv)++resolveVersion' ::+  ( HasLog env+  , MonadReader env m+  , HasGHCupInfo env+  , HasDirs env+  , MonadIOish m+  )+  => SetToolVersion+  -> GuessMode+  -> Tool+  -> Excepts+       '[ TagNotFound+        , DayNotFound+        , NextVerNotFound+        , NoToolVersionSet+        , ParseError+        ] m TargetVersionReq+resolveVersion' SetRecommended _ tool = do+  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo+  fmap (`TargetVersionReq` Nothing) $ getRecommended dls tool ?? TagNotFound Recommended tool+resolveVersion' (SetGHCVersion (TargetVersionReq v rev)) guessMode tool = do+  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo+  tv' <- lift $ guessFullVersion dls v tool guessMode+  pure (TargetVersionReq tv' rev)+resolveVersion' (SetToolVersion (toTargetVersionReq' -> treq)) guessMode tool = do+  let TargetVersionReq v rev = treq+  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo+  tv' <- lift $ guessFullVersion dls v tool guessMode+  pure (TargetVersionReq tv' rev)+resolveVersion' (SetToolTag Latest) _ tool = do+  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo+  fmap (`TargetVersionReq` Nothing) $ getLatest dls tool ?? TagNotFound Latest tool+resolveVersion' (SetToolDay day) _ tool = do+  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo+  case getByReleaseDay dls tool day of+    Left ad -> throwE $ DayNotFound day tool ad+    Right (v, _) -> pure (TargetVersionReq v Nothing)+resolveVersion' (SetToolTag LatestPrerelease) _ tool = do+  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo+  fmap (`TargetVersionReq` Nothing) $ getLatestPrerelease dls tool ?? TagNotFound LatestPrerelease tool+resolveVersion' (SetToolTag LatestNightly) _ tool = do+  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo+  fmap (`TargetVersionReq` Nothing) $ getLatestNightly dls tool ?? TagNotFound LatestNightly tool+resolveVersion' (SetToolTag Recommended) _ tool = do+  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo+  fmap (`TargetVersionReq` Nothing) $ getRecommended dls tool ?? TagNotFound Recommended tool+resolveVersion' (SetToolTag (Base pvp'')) _ t+  | t == ghc = do+      GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo+      fmap (`TargetVersionReq` Nothing) $ getLatestBaseVersion dls pvp'' ?? TagNotFound (Base pvp'') ghc+resolveVersion' SetNext _ tool = do+  set <- liftE $ getSetVersion tool Nothing !!? NoToolVersionSet tool Nothing -- TODO+  vers <- lift $ getInstalledVersions tool Nothing+  next <- (headMay+    . tail+    . dropWhile (/= set)+    . cycle+    . sort+    $ vers) ?? NoToolVersionSet tool Nothing+  let tv = mkTVer . _vrVersion $ next+  pure (TargetVersionReq tv Nothing)+resolveVersion' (SetToolTag t') _ tool =+  throwE $ TagNotFound t' tool++-- | Guess the full version from an input version, by possibly+-- examining the metadata and the installed versions.+--+-- >>> go $ guessFullVersion rr (mkTVer [vver|8|]) GHC GLax+-- "8.10.7"+-- >>> go $ guessFullVersion rr (mkTVer [vver|8.10|]) GHC GLax+-- "8.10.7"+-- >>> go $ guessFullVersion rr (mkTVer [vver|8.10.7|]) GHC GLax+-- "8.10.7"+-- >>> go $ guessFullVersion rr (mkTVer [vver|9.12.1|]) GHC GLax+-- "9.12.1"+-- >>> go $ guessFullVersion rr (mkTVer [vver|8|]) GHC GStrict+-- "8"+guessFullVersion :: ( HasLog env+                    , MonadReader env m+                    , HasDirs env+                    , MonadIOish m+                    )+                 => GHCupDownloads+                 -> TargetVersion+                 -> Tool+                 -> GuessMode+                 -> m TargetVersion+guessFullVersion dls v tool guessMode = do+  case pvp $ prettyVer (_tvVersion v) of -- need to be strict here+    Left _ -> pure v+    Right pvpIn+      | (guessMode /= GStrict) && hasn't (_GHCupDownloads % ix tool % toolVersionsL % ix v) dls -> do+          ghcs <- if guessMode == GLaxWithInstalled then getInstalledTools else pure []+          if v `notElem` ghcs+          then getLatestToolFor tool (_tvTarget v) pvpIn dls >>= \case+                 Just (pvp_, _vm, mt) -> do+                   v' <- pvpToVersion pvp_ ""+                   when (v' /= _tvVersion v) $ logWarn ("Assuming you meant version " <> prettyVer v')+                   pure $ TargetVersion mt v'+                 Nothing -> pure v+          else pure v+    _ -> pure v+ where+  getInstalledTools = fmap _tvrTargetVer <$> getInstalledVersions' tool+++parseUrlSource :: String -> Either String [NewURLSource]+parseUrlSource s = (fromURLSource <$> parseUrlSource' s)+               <|> ((:[]) <$> parseNewUrlSource s)+               <|> parseNewUrlSources s++parseUrlSource' :: String -> Either String URLSource+parseUrlSource' "GHCupURL" = pure GHCupURL+parseUrlSource' "StackSetupURL" = pure StackSetupURL+parseUrlSource' s' = (eitherDecode . LE.encodeUtf8 . LT.pack $ s')+            <|> (fmap (OwnSource . (:[]) . Right) . first show . parseURI . UTF8.fromString $ s')++parseNewUrlSource :: String -> Either String NewURLSource+parseNewUrlSource "GHCupURL" = pure NewGHCupURL+parseNewUrlSource "StackSetupURL" = pure NewStackSetupURL+parseNewUrlSource s' = (fmap NewChannelAlias . parseChannelAlias $ s')+            <|> (eitherDecode . LE.encodeUtf8 . LT.pack $ s')+            <|> (fmap NewURI . first show . parseURI . UTF8.fromString $ s')++parseNewUrlSources :: String -> Either String [NewURLSource]+parseNewUrlSources s = case AP.parseOnly+                              (AP.parseList' <* AP.skipSpaces <* AP.endOfInput)+                              (UTF8.fromString s) of+  Right bs ->+    forM bs $ \b -> AP.parseOnly (parse <* AP.skipSpaces <* AP.endOfInput) b+  Left  e -> Left e+ where+  parse :: AP.Parser NewURLSource+  parse = (NewGHCupURL <$ AP.string "GHCupURL")+      <|> (NewStackSetupURL <$ AP.string "StackSetupURL")+      <|> AP.choice ((\x -> AP.string (UTF8.fromString . T.unpack . channelAliasText $ x) $> NewChannelAlias x) <$> ([minBound..maxBound] :: [ChannelAlias]))+      <|> (NewURI <$> parseURIP)++parseChannelAlias :: String -> Either String ChannelAlias+parseChannelAlias s =+  let aliases = map (\c -> (T.unpack (channelAliasText c), c)) [minBound..maxBound]+  in case lookup s aliases of+    Just c  -> Right c+    Nothing -> Left $ "Unexpected ChannelAlias: " <> s++#if MIN_VERSION_transformers(0,6,0)+instance Alternative (Either [a]) where+    empty        = Left []+    Left _ <|> n = n+    m      <|> _ = m+#endif+
+ lib/GHCup/Input/Parsers/URI.hs view
@@ -0,0 +1,97 @@+{-# LANGUAGE CPP                   #-}+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE DataKinds #-}++{-|+Module      : GHCup.Input.Parsers.URI+Description : GHCup domain specific URI utilities+Copyright   : (c) Julian Ospald, 2024+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable++This module contains GHCup helpers specific to+URI handling.+-}+module GHCup.Input.Parsers.URI where++import GHCup.Types.Optics+import GHCup.Errors++import           Data.Bifunctor (first)+import           Data.Text                      ( Text )+import           Control.Applicative+import           Data.Attoparsec.ByteString+import           Data.ByteString+import           URI.ByteString hiding (parseURI)+import           System.URI.File+import Data.Variant.Excepts (Excepts, throwE)+import Optics (view, preview, (%), _Just)++import qualified Data.Text.Encoding            as E+import qualified Data.Binary.Builder           as B+import qualified Data.ByteString               as BS+import qualified Data.ByteString.Lazy          as L++++    -----------+    --[ URI ]--+    -----------+++parseURI :: ByteString -> Either URIParseError (URIRef Absolute)+parseURI = first OtherError . parseOnly parseURIP++parseURI' :: Text -> Either URIParseError (URIRef Absolute)+parseURI' = first OtherError . parseOnly parseURIP . E.encodeUtf8++parseURIP :: Parser (URIRef Absolute)+parseURIP = do+  ref <- (Right <$> parseFile) <|> (Left <$> uriParser laxURIParserOptions)+  case ref of+    Left (URI { uriScheme = (Scheme "file") }) ->+#if defined(IS_WINDOWS)+      fail "Invalid file URI. File URIs must be absolute (start with a drive letter or UNC path) and not contain backslashes."+#else+      fail "Invalid file URI. File URIs must be absolute."+#endif+    Left o -> pure o+    Right (FileURI (Just _) _) -> fail "File URIs with auth part are not supported!"+    Right (FileURI _ fp) -> pure $ URI (Scheme "file") Nothing fp (Query []) Nothing+ where+  parseFile+#if defined(IS_WINDOWS)+    = fileURIExtendedWindowsP+#else+    = fileURIExtendedPosixP+#endif++-- | Extracts from a URI type: (https?, host, path+query, port)+uriToQuadruple :: Monad m+               => URI+               -> Excepts+                    '[UnsupportedScheme]+                    m+                    (Bool, ByteString, ByteString, Maybe Int)+uriToQuadruple URI {..} = do+  let scheme = view schemeBSL' uriScheme++  host <- maybe (throwE UnsupportedScheme) pure $+    preview (_Just % authorityHostL' % hostBSL') uriAuthority++  https <- if+    | scheme == "https" -> pure True+    | scheme == "http"  -> pure False+    | otherwise         -> throwE UnsupportedScheme++  let queryBS =+        BS.intercalate "&"+          . fmap (\(x, y) -> encodeQuery x <> "=" <> encodeQuery y)+          $ queryPairs uriQuery+      port =+        preview (_Just % authorityPortL' % _Just % portNumberL') uriAuthority+      fullpath = if BS.null queryBS then uriPath else uriPath <> "?" <> queryBS+  pure (https, host, fullpath, port)+  where encodeQuery = L.toStrict . B.toLazyByteString . urlEncodeQuery
+ lib/GHCup/Input/Prompts.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleContexts #-}++module GHCup.Input.Prompts+  ( PromptQuestion,+    PromptResponse (..),+    getUserPromptResponse,+  )+where++import Control.Monad.Reader+import qualified Data.Text as T+import qualified Data.Text.IO as TIO+import GHCup.Prelude.Logger+import GHCup.Types.Optics+import GHCup.Types (PromptQuestion, PromptResponse(..))++getUserPromptResponse :: ( HasLog env+                         , MonadReader env m+                         , MonadIO m)+                      => PromptQuestion+                      -> PromptResponse -- ^ Default response to use if user doesn't type explicit response (e.g. just presses Return)+                      -> m PromptResponse+getUserPromptResponse prompt defaultResponse = do+  logInfo prompt+  resp <- liftIO TIO.getLine+  pure $+    if T.null resp+      then defaultResponse+      else if resp `elem` ["YES", "yes", "y", "Y"]+        then PromptYes+        else PromptNo
+ lib/GHCup/Input/SymlinkSpec.hs view
@@ -0,0 +1,91 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}++module GHCup.Input.SymlinkSpec where++import GHCup.Errors+import GHCup.Query.GHCupDirs+import GHCup.Types+import GHCup.Types.Optics+import GHCup.Prelude.Logger++import Control.Applicative          ( Alternative (many), (<|>) )+import Control.Monad                ( forM )+import Control.Monad.IO.Class       ( liftIO )+import Control.Monad.Reader         ( MonadReader )+import Data.Variant.Excepts         ( Excepts, throwE )+import Data.Versions                ( Version, prettyVer )+import Data.Void                    ( Void )+import System.FilePath              ( takeFileName )+import System.FilePattern.Directory ( getDirectoryFilesIgnore )++import qualified Data.Text       as T+import qualified Text.Megaparsec as MP+++parseSymlinkSpec ::+    Monad m+  => Version+  -> SymlinkSpec String+  -> Excepts+       '[ParseError]+       m+       (SymlinkSpec [Either Char Version])+parseSymlinkSpec ver SymlinkSpec{..} = do+  target <- either (throwE . ParseError . show) pure $ parseDomain _slTarget+  linkName <- either (throwE . ParseError . show) pure $ parseDomain _slLinkName+  setName <- forM _slSetName $ either (throwE . ParseError . show) pure . parseDomain+  pure $ SymlinkSpec target linkName _slPVPMajorLinks setName+ where+   parseDomain = MP.parse domainParser ""++   domainParser :: MP.Parsec Void String [Either Char Version]+   domainParser = many anyOrKnownVars+     where+      -- TODO: make this more efficient+      anyOrKnownVars :: MP.Parsec Void String (Either Char Version)+      anyOrKnownVars = MP.try (fmap (const (Right ver)) (MP.chunk "${PKGVER}"))+                   <|> fmap Left MP.anySingle++substituteSpec :: SymlinkSpec [Either Char Version] -> SymlinkFileSpec+substituteSpec SymlinkSpec{..} =+  let target = mconcat $ either (:[]) (T.unpack . prettyVer) <$> _slTarget+      linkName = mconcat $ either (:[]) (T.unpack . prettyVer) <$> _slLinkName+      setName = mconcat . fmap (either (:[]) (T.unpack . prettyVer)) <$> _slSetName+  in SymlinkSpec target linkName _slPVPMajorLinks setName+++resolveSymlinkSpec  ::+     ( MonadReader env m+     , HasLog env+     , MonadIOish m+     )+  => GHCupPath+  -> SymlinkInputSpec+  -> Excepts+       '[ParseError]+       m+       [SymlinkSpec String]+resolveSymlinkSpec _ SymlinkInputSpec{..} = pure [SymlinkSpec{..}]+resolveSymlinkSpec (fromGHCupPath -> workDir) SymlinkPatternSpec{..} = do+  binaries <- liftIO $ getDirectoryFilesIgnore workDir _slTargetPattern _slTargetPatternIgnore+  logDebug2 $ "Resolved binaries found in " <> T.pack workDir <> ": " <> T.pack (show binaries)+  forM binaries $ \binary -> do+    let _slTarget = binary+    _slLinkName <- parseDomain (takeFileName binary) _slLinkName+    logDebug2 $ "Parsed slLinkName: " <> T.pack _slLinkName+    _slSetName <- forM _slSetName $ parseDomain (takeFileName binary)+    logDebug2 $ "Parsed slSetName: " <> T.pack (show _slSetName)+    pure SymlinkSpec{..}+ where+   parseDomain targetFn = either (throwE . ParseError . show) pure . MP.parse (domainParser targetFn) ""++   domainParser :: FilePath -> MP.Parsec Void String String+   domainParser targetFn = concat <$> many anyOrKnownVars+     where+      -- TODO: make this more efficient+      anyOrKnownVars :: MP.Parsec Void String String+      anyOrKnownVars = MP.try (fmap (const targetFn) (MP.chunk "${TARGETFN}"))+                   <|> fmap (:[]) MP.anySingle+
+ lib/GHCup/Legacy/Cabal.hs view
@@ -0,0 +1,132 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}++{-|+Module      : GHCup.Legacy.Cabal+Description : GHCup legacy installation functions for Cabal+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Legacy.Cabal where++import GHCup.Errors+import GHCup.Legacy.Utils+import GHCup.Prelude+import GHCup.Types+import GHCup.System.Directory+import GHCup.Types.Optics++import Control.Applicative+import Control.Exception.Safe+import Control.Monad+#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Monad.Reader+import Control.Monad.Trans.Resource hiding ( throwM )+import Data.Either+import Data.List+import Data.Maybe+import Data.Ord+import Data.Variant.Excepts+import Data.Versions                hiding ( patch )+import Prelude                      hiding ( abs, writeFile )+import Safe                         hiding ( at )+import System.FilePath+import System.IO.Error++import qualified Data.Text as T+++++    -----------------+    --[ Set cabal ]--+    -----------------+++-- | Set the @~\/.ghcup\/bin\/cabal@ symlink.+setCabal :: ( MonadMask m+            , MonadReader env m+            , HasDirs env+            , HasLog env+            , MonadFail m+            , MonadIO m+            , MonadUnliftIO m)+         => Version+         -> Maybe FilePath+         -> Excepts '[NotInstalled] m ()+setCabal ver mTmpDir = do+  let targetFile = "cabal-" <> T.unpack (prettyVer ver) <> exeExt++  -- symlink destination+  Dirs {..} <- lift getDirs++  whenM (liftIO $ not <$> doesFileExist (binDir </> targetFile))+    $ throwE+    $ NotInstalled cabal (TargetVersion Nothing ver)++  let cabalbin = fromMaybe binDir mTmpDir </> "cabal" <> exeExt++  -- create link+  let destL = targetFile+  lift $ createLink destL cabalbin++  liftIO (isShadowed cabalbin) >>= \case+    Nothing -> pure ()+    Just pa -> lift $ logWarn $ T.pack $ prettyHFError (ToolShadowed cabal ver [(pa, cabalbin)])++  pure ()++unsetCabal :: ( MonadMask m+              , MonadReader env m+              , HasDirs env+              , MonadIO m)+           => m ()+unsetCabal = do+  Dirs {..} <- getDirs+  let cabalbin = binDir </> "cabal" <> exeExt+  hideError doesNotExistErrorType $ rmLink cabalbin+++    ----------------+    --[ Rm cabal ]--+    ----------------+++-- | Delete a cabal version. Will try to fix the @cabal@ symlink+-- after removal (e.g. setting it to an older version).+rmCabalVer :: ( MonadMask m+              , MonadReader env m+              , HasDirs env+              , MonadThrow m+              , HasLog env+              , MonadIO m+              , MonadFail m+              , MonadCatch m+              , MonadUnliftIO m+              )+           => Version+           -> Excepts '[NotInstalled] m ()+rmCabalVer ver = do+  whenM (lift $ fmap not $ cabalInstalled ver) $ throwE (NotInstalled cabal (TargetVersion Nothing ver))++  cSet      <- lift cabalSet++  Dirs {..} <- lift getDirs++  let cabalFile = "cabal-" <> T.unpack (prettyVer ver) <> exeExt+  lift $ hideError doesNotExistErrorType $ recycleFile (binDir </> cabalFile)++  when (Just ver == cSet) $ do+    cVers <- lift $ fmap rights getInstalledCabals+    case headMay . sortBy (comparing Down) $ cVers of+      Just latestver -> setCabal latestver Nothing+      Nothing        -> lift $ rmLink (binDir </> "cabal" <> exeExt)
+ lib/GHCup/Legacy/HLS.hs view
@@ -0,0 +1,277 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}++{-|+Module      : GHCup.Legacy.HLS+Description : GHCup installation functions for legacy HLS+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Legacy.HLS where++import GHCup.Errors+import GHCup.Legacy.Utils+import GHCup.Prelude+import GHCup.Prelude.String.QQ+import GHCup.Query.DB+import GHCup.Query.GHCupDirs+import GHCup.System.Directory+import GHCup.Types+import GHCup.Types.Optics++import Control.Applicative+import Control.Exception.Safe+import Control.Monad+#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Monad.Reader+import Control.Monad.Trans.Resource hiding ( throwM )+import Data.ByteString              ( ByteString )+import Data.Either+import Data.List+import Data.Maybe+import Data.Ord+import Data.Variant.Excepts+import Data.Versions                hiding ( patch )+import GHC.IO.Exception+import Prelude                      hiding ( abs, writeFile )+import Safe                         hiding ( at )+import System.FilePath+import System.IO.Error+import Text.Regex.Posix++import qualified Data.Text       as T+import qualified Text.Megaparsec as MP++++    --------------------+    --[ Installation ]--+    --------------------++++-- | Install an unpacked hls distribution (legacy).+installHLSUnpackedLegacy :: (MonadReader env m, MonadFail m, HasLog env, MonadCatch m, MonadIO m)+                         => FilePath      -- ^ Path to the unpacked hls bindist (where the executable resides)+                         -> InstallDirResolved      -- ^ Path to install to+                         -> Version+                         -> Bool          -- ^ is it a force install+                         -> Excepts '[CopyError, FileAlreadyExistsError] m ()+installHLSUnpackedLegacy path installDir ver forceInstall = do+  lift $ logInfo "Installing HLS"+  liftIO $ createDirRecursive' (fromInstallDir installDir)++  lift $ logInfo $ "Install binaries from " <> T.pack path+  -- install haskell-language-server-<ghcver>+  bins@(_:_) <- liftIO $ findFiles+    path+    (makeRegexOpts compExtended+                   execBlank+                   ([s|^haskell-language-server-[0-9].*$|] :: ByteString)+    )++  lift $ logInfo $ "Found binaries " <> T.pack (show bins)+  forM_ bins $ \f -> do+    let toF = dropSuffix exeExt f+              <> (case installDir of+                   IsolateDirResolved _ -> ""+                   _                    -> ("~" <>) . T.unpack . prettyVer $ ver+                 )+              <> exeExt++    let srcPath = path </> f+    let destPath = fromInstallDir installDir </> toF++    -- destination could be an existing symlink+    -- for new make-based HLSes+    liftIO $ rmFileForce destPath++    copyFileE+      srcPath+      destPath+      (not forceInstall)+    lift $ chmod_755 destPath++  -- install haskell-language-server-wrapper+  let wrapper = "haskell-language-server-wrapper"+      toF = wrapper+            <> (case installDir of+                 IsolateDirResolved _ -> ""+                 _                    -> ("-" <>) . T.unpack . prettyVer $ ver+               )+            <> exeExt+      srcWrapperPath = path </> wrapper <> exeExt+      destWrapperPath = fromInstallDir installDir </> toF++  liftIO $ rmFileForce destWrapperPath+  copyFileE+    srcWrapperPath+    destWrapperPath+    (not forceInstall)++  lift $ chmod_755 destWrapperPath++++-- | Installs hls binaries @haskell-language-server-\<ghcver\>@+-- into @~\/.ghcup\/bin/@, as well as @haskell-languager-server-wrapper@.++++    -----------------+    --[ Set/Unset ]--+    -----------------++-- | Set the haskell-language-server symlinks.+setHLS :: ( MonadReader env m+          , HasDirs env+          , HasLog env+          , MonadIO m+          , MonadMask m+          , MonadFail m+          , MonadUnliftIO m+          )+       => Version+       -> SetHLS+       -> Maybe FilePath  -- if set, signals that we're not operating in ~/.ghcup/bin+                          -- and don't want mess with other versions+       -> Excepts '[NotInstalled] m ()+setHLS ver shls mBinDir = do+  whenM (lift $ not <$> hlsInstalled ver) (throwE (NotInstalled hls (TargetVersion Nothing ver)))++  -- symlink destination+  binDir <- case mBinDir of+    Just x -> pure x+    Nothing -> do+      Dirs {binDir = f} <- lift getDirs+      pure f++  -- first delete the old symlinks+  when (isNothing mBinDir) $+    case shls of+      -- not for legacy+      SetHLS_XYZ -> liftE $ rmMinorHLSSymlinks ver+      -- legacy and new+      SetHLSOnly -> liftE rmPlainHLS++  case shls of+    -- not for legacy+    SetHLS_XYZ -> do+      bins <- lift $ hlsInternalServerScripts ver Nothing++      forM_ bins $ \f -> do+        let fname = takeFileName f+        destL <- binarySymLinkDestination binDir f+        let target = if "haskell-language-server-wrapper" `isPrefixOf` fname+                     then fname <> "-" <> T.unpack (prettyVer ver) <> exeExt+                     else fname <> "~" <> T.unpack (prettyVer ver) <> exeExt+        lift $ createLink destL (binDir </> target)++    -- legacy and new+    SetHLSOnly -> do+      -- set haskell-language-server-<ghcver> symlinks+      bins <- lift $ hlsServerBinaries ver Nothing+      when (null bins) $ throwE $ NotInstalled hls (TargetVersion Nothing ver)++      forM_ bins $ \f -> do+        let destL = f+        let target = (<> exeExt) . head . splitOn "~" $ f+        lift $ createLink destL (binDir </> target)++      -- set haskell-language-server-wrapper symlink+      let destL = "haskell-language-server-wrapper-" <> T.unpack (prettyVer ver) <> exeExt+      let wrapper = binDir </> "haskell-language-server-wrapper" <> exeExt++      lift $ createLink destL wrapper++      when (isNothing mBinDir) $+        lift warnAboutHlsCompatibility++      liftIO (isShadowed wrapper) >>= \case+        Nothing -> pure ()+        Just pa -> lift $ logWarn $ T.pack $ prettyHFError (ToolShadowed hls ver [(pa, wrapper)])+++unsetHLS :: ( MonadMask m+            , MonadReader env m+            , HasDirs env+            , MonadIO m)+         => m ()+unsetHLS = do+  Dirs {..} <- getDirs+  let wrapper = binDir </> "haskell-language-server-wrapper" <> exeExt+  bins   <- liftIO $ handleIO (\_ -> pure []) $ findFiles'+    binDir+    (MP.chunk "haskell-language-server-" <* pvp' <* MP.chunk (T.pack exeExt) <* MP.eof)+  forM_ bins (hideError doesNotExistErrorType . rmLink . (binDir </>))+  hideError doesNotExistErrorType $ rmLink wrapper+++++    ---------------+    --[ Removal ]--+    ---------------+++-- | Delete a hls version. Will try to fix the hls symlinks+-- after removal (e.g. setting it to an older version).+rmHLSVer :: ( MonadMask m+            , MonadReader env m+            , HasDirs env+            , MonadThrow m+            , HasLog env+            , MonadIO m+            , MonadFail m+            , MonadCatch m+            , MonadUnliftIO m+            )+         => Version+         -> Excepts '[NotInstalled, UninstallFailed] m ()+rmHLSVer ver = do+  whenM (lift $ fmap not $ hlsInstalled ver) $ throwE (NotInstalled hls (TargetVersion Nothing ver))++  isHlsSet <- lift hlsSet++  liftE $ rmMinorHLSSymlinks ver++  when (Just ver == isHlsSet) $ do+    -- delete all set symlinks+    liftE rmPlainHLS++  hlsDir' <- ghcupHLSDir ver+  let hlsDir = fromGHCupPath hlsDir'+  lift (getInstalledFiles hls (mkTVer ver)) >>= \case+    Just files -> do+      lift $ logInfo $ "Removing files safely from: " <> T.pack hlsDir+      forM_ files (lift . hideError NoSuchThing . recycleFile . (\f -> hlsDir </> dropDrive f))+      removeEmptyDirsRecursive hlsDir+      survivors <- liftIO $ hideErrorDef [doesNotExistErrorType] [] $ listDirectory hlsDir+      f <- recordedInstallationFile hls (mkTVer ver)+      lift $ recycleFile f+      when (not (null survivors)) $ throwE $ UninstallFailed hlsDir survivors+    Nothing -> do+      isDir <- liftIO $ doesDirectoryExist hlsDir+      isSyml <- liftIO $ handleIO (\_ -> pure False) $ pathIsSymbolicLink hlsDir+      when (isDir && not isSyml) $ do+        lift $ logInfo $ "Removing legacy directory recursively: " <> T.pack hlsDir+        recyclePathForcibly hlsDir'++  when (Just ver == isHlsSet) $ do+    -- set latest hls+    hlsVers <- lift $ fmap rights getInstalledHLSs+    case headMay . sortBy (comparing Down) $ hlsVers of+      Just latestver -> liftE $ setHLS latestver SetHLSOnly Nothing+      Nothing        -> pure ()++
+ lib/GHCup/Legacy/Stack.hs view
@@ -0,0 +1,131 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}++{-|+Module      : GHCup.Legacy.Stack+Description : GHCup legacy installation functions for Stack+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Legacy.Stack where++import GHCup.Errors+import GHCup.Legacy.Utils+import GHCup.Prelude+import GHCup.System.Directory+import GHCup.Types+import GHCup.Types.Optics++import Control.Applicative+import Control.Exception.Safe+import Control.Monad+#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Monad.Reader+import Control.Monad.Trans.Resource hiding ( throwM )+import Data.Either+import Data.List+import Data.Maybe+import Data.Ord+import Data.Variant.Excepts+import Data.Versions                hiding ( patch )+import Prelude                      hiding ( abs, writeFile )+import Safe                         hiding ( at )+import System.FilePath+import System.IO.Error++import qualified Data.Text as T++++    -----------------+    --[ Set stack ]--+    -----------------+++-- | Set the @~\/.ghcup\/bin\/stack@ symlink.+setStack :: ( MonadMask m+            , MonadReader env m+            , HasDirs env+            , HasLog env+            , MonadThrow m+            , MonadFail m+            , MonadIO m+            , MonadUnliftIO m+            )+         => Version+         -> Maybe FilePath+         -> Excepts '[NotInstalled] m ()+setStack ver mTmpDir = do+  let targetFile = "stack-" <> T.unpack (prettyVer ver) <> exeExt++  -- symlink destination+  Dirs {..} <- lift getDirs++  whenM (liftIO $ not <$> doesFileExist (binDir </> targetFile))+    $ throwE+    $ NotInstalled stack (TargetVersion Nothing ver)++  let stackbin = fromMaybe binDir mTmpDir </> "stack" <> exeExt++  lift $ createLink targetFile stackbin++  liftIO (isShadowed stackbin) >>= \case+    Nothing -> pure ()+    Just pa -> lift $ logWarn $ T.pack $ prettyHFError (ToolShadowed stack ver [(pa, stackbin)])++  pure ()+++unsetStack :: ( MonadMask m+              , MonadReader env m+              , HasDirs env+              , MonadIO m)+           => m ()+unsetStack = do+  Dirs {..} <- getDirs+  let stackbin = binDir </> "stack" <> exeExt+  hideError doesNotExistErrorType $ rmLink stackbin+++    ----------------+    --[ Rm stack ]--+    ----------------++-- | Delete a stack version. Will try to fix the @stack@ symlink+-- after removal (e.g. setting it to an older version).+rmStackVer :: ( MonadMask m+              , MonadReader env m+              , HasDirs env+              , MonadThrow m+              , HasLog env+              , MonadIO m+              , MonadFail m+              , MonadCatch m+              , MonadUnliftIO m+              )+           => Version+           -> Excepts '[NotInstalled] m ()+rmStackVer ver = do+  whenM (lift $ fmap not $ stackInstalled ver) $ throwE (NotInstalled stack (TargetVersion Nothing ver))++  sSet      <- lift stackSet++  Dirs {..} <- lift getDirs++  let stackFile = "stack-" <> T.unpack (prettyVer ver) <> exeExt+  lift $ hideError doesNotExistErrorType $ recycleFile (binDir </> stackFile)++  when (Just ver == sSet) $ do+    sVers <- lift $ fmap rights getInstalledStacks+    case headMay . sortBy (comparing Down) $ sVers of+      Just latestver -> setStack latestver Nothing+      Nothing        -> lift $ rmLink (binDir </> "stack" <> exeExt)
+ lib/GHCup/Legacy/Utils.hs view
@@ -0,0 +1,700 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ViewPatterns #-}++{-|+Module      : GHCup.Legacy.Utils+Description : GHCup domain specific legacy utilities+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable++This module contains GHCup helpers specific to+installation and introspection of files/versions etc.+-}+module GHCup.Legacy.Utils where+++#if defined(IS_WINDOWS)+import GHCup.Prelude.Windows+#else+import GHCup.Prelude.Posix+#endif+import Control.Applicative+import Control.Exception.Safe+import Control.Monad+import GHCup.Errors+import GHCup.Prelude+import GHCup.Prelude.MegaParsec+import GHCup.Prelude.String.QQ+import GHCup.Query.GHCupDirs+import GHCup.System.Directory+import GHCup.Types+import GHCup.Types.JSON+    (safeVersion, cabalBadNames)+import GHCup.Types.Optics+import qualified GHCup.Warnings as Warnings++#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Monad.Reader+import Data.ByteString                ( ByteString )+import Data.Either+import Data.List+    ( groupBy, isInfixOf, isPrefixOf, isSuffixOf, nub, sortBy, stripPrefix )+import Data.Maybe+import Data.Text                      ( Text )+import Data.Variant.Excepts+import Data.Versions                  hiding ( patch )+import GHC.IO.Exception+import Safe+import System.FilePath+import System.IO.Error+import Text.Regex.Posix++import qualified Data.Text          as T+import qualified Data.Text.Encoding as E+import qualified Text.Megaparsec    as MP+++++    ------------------------+    --[ Symlink handling ]--+    ------------------------+++-- | Create a relative symlink destination for the binary directory,+-- given a target toolpath.+binarySymLinkDestination :: ( MonadThrow m+                            , MonadIO m+                            )+                         => FilePath -- ^ binary dir+                         -> FilePath -- ^ the full toolpath+                         -> m FilePath+binarySymLinkDestination binDir toolPath = do+  toolPath' <- liftIO $ canonicalizePath toolPath+  binDir' <- liftIO $ canonicalizePath binDir+  pure (relativeSymlink binDir' toolPath')+++-- | Removes the minor GHC symlinks, e.g. ghc-8.6.5.+rmMinorGHCSymlinks :: ( MonadReader env m+                      , HasDirs env+                      , MonadIO m+                      , HasLog env+                      , MonadThrow m+                      , MonadFail m+                      , MonadMask m+                      )+                   => TargetVersion+                   -> Excepts '[NotInstalled] m ()+rmMinorGHCSymlinks tv@TargetVersion{..} = do+  Dirs {..}  <- lift getDirs++  files                         <- liftE $ ghcToolFiles tv+  forM_ files $ \f -> do+    let f_xyz = f <> "-" <> T.unpack (prettyVer _tvVersion) <> exeExt+    let fullF = binDir </> f_xyz+    lift $ logDebug ("rm -f " <> T.pack fullF)+    lift $ hideError doesNotExistErrorType $ rmLink fullF+++-- | Removes the set ghc version for the given target, if any.+rmPlainGHC :: ( MonadReader env m+              , HasDirs env+              , HasLog env+              , MonadThrow m+              , MonadFail m+              , MonadIO m+              , MonadMask m+              )+           => Maybe Text -- ^ target+           -> Excepts '[NotInstalled] m ()+rmPlainGHC target = do+  Dirs {..}  <- lift getDirs+  mtv                           <- lift $ ghcSet target+  forM_ mtv $ \tv -> do+    files <- liftE $ ghcToolFiles tv+    forM_ files $ \f -> do+      let fullF = binDir </> f <> exeExt+      lift $ logDebug ("rm -f " <> T.pack fullF)+      lift $ hideError doesNotExistErrorType $ rmLink fullF+    -- old ghcup+    let hdc_file = binDir </> "haddock-ghc" <> exeExt+    lift $ logDebug ("rm -f " <> T.pack hdc_file)+    lift $ hideError doesNotExistErrorType $ rmLink hdc_file+++-- | Remove the major GHC symlink, e.g. ghc-8.6.+rmMajorGHCSymlinks :: ( MonadReader env m+                      , HasDirs env+                      , MonadIO m+                      , HasLog env+                      , MonadThrow m+                      , MonadFail m+                      , MonadMask m+                      )+                   => TargetVersion+                   -> Excepts '[NotInstalled] m ()+rmMajorGHCSymlinks tv@TargetVersion{..} = do+  Dirs {..}  <- lift getDirs+  (mj, mi) <- getMajorMinorV _tvVersion+  let v' = intToText mj <> "." <> intToText mi++  files                         <- liftE $ ghcToolFiles tv+  forM_ files $ \f -> do+    let f_xy = f <> "-" <> T.unpack v' <> exeExt+    let fullF = binDir </> f_xy+    lift $ logDebug ("rm -f " <> T.pack fullF)+    lift $ hideError doesNotExistErrorType $ rmLink fullF++++-- | Removes the minor HLS files, e.g. 'haskell-language-server-8.10.7~1.6.1.0'+-- and 'haskell-language-server-wrapper-1.6.1.0'.+rmMinorHLSSymlinks :: ( MonadReader env m+                      , HasDirs env+                      , MonadIO m+                      , HasLog env+                      , MonadThrow m+                      , MonadFail m+                      , MonadMask m+                      )+                   => Version+                   -> Excepts '[NotInstalled] m ()+rmMinorHLSSymlinks ver = do+  Dirs {..}  <- lift getDirs++  hlsBins <- hlsAllBinaries ver+  forM_ hlsBins $ \f -> do+    let fullF = binDir </> f+    lift $ logDebug ("rm -f " <> T.pack fullF)+    -- on unix, this may be either a file (legacy) or a symlink+    -- on windows, this is always a file... hence 'rmFile'+    -- works consistently across platforms+    lift $ rmFile fullF++-- | Removes the set HLS version, if any.+rmPlainHLS :: ( MonadReader env m+              , HasDirs env+              , HasLog env+              , MonadThrow m+              , MonadFail m+              , MonadIO m+              , MonadMask m+              )+           => Excepts '[NotInstalled] m ()+rmPlainHLS = do+  Dirs {..}  <- lift getDirs++  -- delete 'haskell-language-server-8.10.7'+  hlsBins <- fmap (filter (\f -> not ("haskell-language-server-wrapper" `isPrefixOf` f) && ('~' `notElem` f)))+    $ liftIO $ handleIO (\_ -> pure []) $ findFiles+      binDir+      (makeRegexOpts compExtended execBlank ([s|^haskell-language-server-.*$|] :: ByteString))+  forM_ hlsBins $ \f -> do+    let fullF = binDir </> f+    lift $ logDebug ("rm -f " <> T.pack fullF)+    if isWindows+    then lift $ rmLink fullF+    else lift $ rmFile fullF++  -- 'haskell-language-server-wrapper'+  let hlswrapper = binDir </> "haskell-language-server-wrapper" <> exeExt+  lift $ logDebug ("rm -f " <> T.pack hlswrapper)+  if isWindows+  then lift $ hideError doesNotExistErrorType $ rmLink hlswrapper+  else lift $ hideError doesNotExistErrorType $ rmFile hlswrapper++++    -----------------------------------+    --[ Set/Installed introspection ]--+    -----------------------------------+++-- | Whether the given GHC version is installed.+ghcInstalled :: (MonadIO m, MonadReader env m, HasDirs env, MonadThrow m) => TargetVersion -> m Bool+ghcInstalled ver = do+  ghcdir <- ghcupGHCDir ver+  liftIO $ doesDirectoryExist (fromGHCupPath ghcdir)+++-- | Whether the given GHC version is set as the current.+ghcSet :: (MonadReader env m, HasDirs env, MonadThrow m, MonadIO m)+       => Maybe Text   -- ^ the target of the GHC version, if any+                       --  (e.g. armv7-unknown-linux-gnueabihf)+       -> m (Maybe TargetVersion)+ghcSet mtarget = do+  Dirs {..}  <- getDirs+  let ghc' = maybe "ghc" (\t -> T.unpack t <> "-ghc") mtarget+  let ghcBin = binDir </> ghc' <> exeExt++  -- link destination is of the form ../ghc/<ver>/bin/ghc+  -- for old ghcup, it is ../ghc/<ver>/bin/ghc-<ver>+  liftIO $ handleIO' NoSuchThing (\_ -> pure Nothing) $ do+    link <- liftIO $ getLinkTarget ghcBin+    Just <$> ghcLinkVersion' link+ where+  ghcLinkVersion' :: MonadThrow m => FilePath -> m TargetVersion+  ghcLinkVersion' (T.pack . dropSuffix exeExt -> t) = throwEither $+    MP.parse (MP.try ghcVersionFromPath <|> ghcLinkVersion) "ghcLinkVersion" t++-- | Get all installed GHCs by reading ~/.ghcup/ghc/<dir>.+-- If a dir cannot be parsed, returns left.+getInstalledGHCs :: (MonadReader env m, HasDirs env, MonadIO m) => m [Either FilePath TargetVersion]+getInstalledGHCs = filter (either (const True) safeVersion) <$> do+  ghcdir <- ghcupGHCBaseDir+  fs     <- liftIO $ hideErrorDef [NoSuchThing] [] $ listDirectoryDirs (fromGHCupPath ghcdir)+  forM fs $ \f -> case parseGHCupGHCDir f of+    Right r -> pure $ Right r+    Left  _ -> pure $ Left f+++-- | Get all installed cabals, by matching on @~\/.ghcup\/bin/cabal-*@.+getInstalledCabals :: ( MonadReader env m+                      , HasDirs env+                      , MonadIO m+                      , MonadCatch m+                      )+                   => m [Either FilePath Version]+getInstalledCabals = filter (either (const True) (safeVersion . mkTVer)) <$> do+  Dirs {..} <- getDirs+  bins   <- liftIO $ handleIO (\_ -> pure []) $ findFiles+    binDir+    (makeRegexOpts compExtended execBlank ([s|^cabal-.*$|] :: ByteString))+  vs <- forM bins $ \f -> case version . T.pack <$> (stripSuffix exeExt =<< stripPrefix "cabal-" f) of+    Just (Right r)+      | T.unpack (prettyVer r) `notPrefixElem` cabalBadNames -> pure $ Right r+      | otherwise -> pure $ Left f+    Just (Left  _) -> pure $ Left f+    Nothing        -> pure $ Left f+  pure $ nub vs+ where+  notPrefixElem a xs = not (any (`isPrefixOf` a) xs)+++-- | Whether the given cabal version is installed.+cabalInstalled :: (MonadIO m, MonadReader env m, HasDirs env, MonadCatch m) => Version -> m Bool+cabalInstalled ver = do+  vers <- fmap rights getInstalledCabals+  pure $ elem ver vers+++-- Return the currently set cabal version, if any.+cabalSet :: (HasLog env, MonadReader env m, HasDirs env, MonadIO m, MonadThrow m, MonadCatch m) => m (Maybe Version)+cabalSet = do+  Dirs {..}  <- getDirs+  let cabalbin = binDir </> "cabal" <> exeExt++  handleIO' NoSuchThing (\_ -> pure Nothing) $ do+    broken <- liftIO $ isBrokenSymlink cabalbin+    if broken+      then do+        logWarn $ "Broken symlink at " <> T.pack cabalbin+        pure Nothing+      else do+        link <- liftIO+          $ handleIO' InvalidArgument+            (\e -> pure $ Left (toException e))+          $ fmap Right $ getLinkTarget cabalbin+        case linkVersion =<< link of+          Right v -> pure $ Just v+          Left err -> do+            logWarn $ "Failed to parse cabal symlink target with: "+              <> T.pack (displayException err)+              <> ". The symlink "+              <> T.pack cabalbin+              <> " needs to point to valid cabal binary, such as 'cabal-3.4.0.0'."+            pure Nothing+ where+  -- We try to be extra permissive with link destination parsing,+  -- because of:+  --   https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/119+  linkVersion :: MonadThrow m => FilePath -> m Version+  linkVersion = throwEither . MP.parse parser "linkVersion" . T.pack . dropSuffix exeExt++  parser+    =   MP.try (stripAbsolutePath *> cabalParse)+    <|> MP.try (stripRelativePath *> cabalParse)+    <|> cabalParse+    <|> (_tvVersion <$> toolVersionFromPath cabal)+  -- parses the version of "cabal-3.2.0.0" -> "3.2.0.0"+  cabalParse = MP.chunk "cabal-" *> version'+  -- parses any path component ending with path separator,+  -- e.g. "foo/"+  stripPathComponent = parseUntil1 pathSep *> MP.some pathSep+  -- parses an absolute path up until the last path separator,+  -- e.g. "/bar/baz/foo" -> "/bar/baz/", leaving "foo"+  stripAbsolutePath = MP.some pathSep *> MP.many (MP.try stripPathComponent)+  -- parses a relative path up until the last path separator,+  -- e.g. "bar/baz/foo" -> "bar/baz/", leaving "foo"+  stripRelativePath = MP.many (MP.try stripPathComponent)++++-- | Get all installed hls, by matching on+-- @~\/.ghcup\/bin/haskell-language-server-wrapper-<\hlsver\>@,+-- as well as @~\/.ghcup\/hls\/<\hlsver\>@+getInstalledHLSs :: (MonadReader env m, HasDirs env, MonadIO m, MonadCatch m)+                 => m [Either FilePath Version]+getInstalledHLSs = filter (either (const True) (safeVersion . mkTVer)) <$> do+  Dirs {..}  <- getDirs+  bins                          <- liftIO $ handleIO (\_ -> pure []) $ findFiles+    binDir+    (makeRegexOpts compExtended+                   execBlank+                   ([s|^haskell-language-server-wrapper-.*$|] :: ByteString)+    )+  legacy <- forM bins $ \f ->+    case+          version . T.pack <$> (stripSuffix exeExt =<< stripPrefix "haskell-language-server-wrapper-" f)+      of+        Just (Right r) -> pure $ Right r+        Just (Left  _) -> pure $ Left f+        Nothing        -> pure $ Left f++  hlsdir <- ghcupHLSBaseDir+  fs     <- liftIO $ hideErrorDef [NoSuchThing] [] $ listDirectoryDirs (fromGHCupPath hlsdir)+  new <- forM fs $ \f -> case parseGHCupHLSDir f of+    Right r -> pure $ Right r+    Left  _ -> pure $ Left f+  pure (nub (new <> legacy))+++-- | Get all installed stacks, by matching on+-- @~\/.ghcup\/bin/stack-<\stackver\>@.+getInstalledStacks :: (MonadReader env m, HasDirs env, MonadIO m, MonadCatch m)+                   => m [Either FilePath Version]+getInstalledStacks = filter (either (const True) (safeVersion . mkTVer)) <$> do+  Dirs {..}  <- getDirs+  bins                          <- liftIO $ handleIO (\_ -> pure []) $ findFiles+    binDir+    (makeRegexOpts compExtended+                   execBlank+                   ([s|^stack-.*$|] :: ByteString)+    )+  forM bins $ \f ->+    case version . T.pack <$> (stripSuffix exeExt =<< stripPrefix "stack-" f) of+        Just (Right r) -> pure $ Right r+        Just (Left  _) -> pure $ Left f+        Nothing        -> pure $ Left f++-- Return the currently set stack version, if any.+stackSet :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m, MonadCatch m, HasLog env) => m (Maybe Version)+stackSet = do+  Dirs {..}  <- getDirs+  let stackBin = binDir </> "stack" <> exeExt++  handleIO' NoSuchThing (\_ -> pure Nothing) $ do+    broken <- liftIO $ isBrokenSymlink stackBin+    if broken+      then do+        logWarn $ "Broken symlink at " <> T.pack stackBin+        pure Nothing+      else do+        link <- liftIO+          $ handleIO' InvalidArgument+            (\e -> pure $ Left (toException e))+          $ fmap Right $ getLinkTarget stackBin+        case linkVersion =<< link of+          Right v -> pure $ Just v+          Left err -> do+            logWarn $ "Failed to parse stack symlink target with: "+              <> T.pack (displayException err)+              <> ". The symlink "+              <> T.pack stackBin+              <> " needs to point to valid stack binary, such as 'stack-2.7.1'."+            pure Nothing+ where+  linkVersion :: MonadThrow m => FilePath -> m Version+  linkVersion = throwEither . MP.parse parser "" . T.pack . dropSuffix exeExt+   where+    parser+      =   MP.try (stripAbsolutePath *> cabalParse)+      <|> MP.try (stripRelativePath *> cabalParse)+      <|> cabalParse+      <|> (_tvVersion <$> toolVersionFromPath stack)+    -- parses the version of "stack-2.7.1" -> "2.7.1"+    cabalParse = MP.chunk "stack-" *> version'+    -- parses any path component ending with path separator,+    -- e.g. "foo/"+    stripPathComponent = parseUntil1 pathSep *> MP.some pathSep+    -- parses an absolute path up until the last path separator,+    -- e.g. "/bar/baz/foo" -> "/bar/baz/", leaving "foo"+    stripAbsolutePath = MP.some pathSep *> MP.many (MP.try stripPathComponent)+    -- parses a relative path up until the last path separator,+    -- e.g. "bar/baz/foo" -> "bar/baz/", leaving "foo"+    stripRelativePath = MP.many (MP.try stripPathComponent)++-- | Whether the given Stack version is installed.+stackInstalled :: (MonadIO m, MonadReader env m, HasDirs env, MonadCatch m) => Version -> m Bool+stackInstalled ver = do+  vers <- fmap rights getInstalledStacks+  pure $ elem ver vers++-- | Whether the given HLS version is installed.+hlsInstalled :: (MonadIO m, MonadReader env m, HasDirs env, MonadCatch m) => Version -> m Bool+hlsInstalled ver = do+  vers <- fmap rights getInstalledHLSs+  pure $ elem ver vers++isLegacyHLS :: (MonadIO m, MonadReader env m, HasDirs env, MonadCatch m) => Version -> m Bool+isLegacyHLS ver = do+  bdir <- ghcupHLSDir ver+  not <$> liftIO (doesDirectoryExist $ fromGHCupPath bdir)+++-- Return the currently set hls version, if any.+hlsSet :: (HasLog env, MonadReader env m, HasDirs env, MonadIO m, MonadThrow m, MonadCatch m) => m (Maybe Version)+hlsSet = do+  Dirs {..}  <- getDirs+  let hlsBin = binDir </> "haskell-language-server-wrapper" <> exeExt++  handleIO' NoSuchThing (\_ -> pure Nothing) $ do+    broken <- liftIO $ isBrokenSymlink hlsBin+    if broken+      then do+        logWarn $ "Broken symlink at " <> T.pack hlsBin+        pure Nothing+      else do+        link <- liftIO $ getLinkTarget hlsBin+        Just <$> linkVersion link+ where+  linkVersion :: MonadThrow m => FilePath -> m Version+  linkVersion = throwEither . MP.parse parser "" . T.pack . dropSuffix exeExt+   where+    parser+      =   MP.try (stripAbsolutePath *> cabalParse)+      <|> MP.try (stripRelativePath *> cabalParse)+      <|> cabalParse+      <|> (_tvVersion <$> toolVersionFromPath hls)+    -- parses the version of "haskell-language-server-wrapper-1.1.0" -> "1.1.0"+    cabalParse = MP.chunk "haskell-language-server-wrapper-" *> version'+    -- parses any path component ending with path separator,+    -- e.g. "foo/"+    stripPathComponent = parseUntil1 pathSep *> MP.some pathSep+    -- parses an absolute path up until the last path separator,+    -- e.g. "/bar/baz/foo" -> "/bar/baz/", leaving "foo"+    stripAbsolutePath = MP.some pathSep *> MP.many (MP.try stripPathComponent)+    -- parses a relative path up until the last path separator,+    -- e.g. "bar/baz/foo" -> "bar/baz/", leaving "foo"+    stripRelativePath = MP.many (MP.try stripPathComponent)+++-- | Return the GHC versions the currently selected HLS supports.+hlsGHCVersions :: ( MonadReader env m+                  , HasDirs env+                  , HasLog env+                  , MonadIO m+                  , MonadThrow m+                  , MonadCatch m+                  )+               => m [Version]+hlsGHCVersions = do+  h <- hlsSet+  fromMaybe [] <$> forM h hlsGHCVersions'+++hlsGHCVersions' :: ( MonadReader env m+                   , HasDirs env+                   , MonadIO m+                   , MonadThrow m+                   , MonadCatch m+                   )+                => Version+                -> m [Version]+hlsGHCVersions' v' = do+  bins <- hlsServerBinaries v' Nothing+  let vers = fmap+        (version+          . T.pack+          . fromJust+          . stripPrefix "haskell-language-server-"+          . head+          . splitOn "~"+          )+        bins+  pure . sortBy (flip compare) . rights $ vers+++-- | Get all server binaries for an hls version from the ~/.ghcup/bin directory, if any.+hlsServerBinaries :: (MonadReader env m, HasDirs env, MonadIO m)+                  => Version+                  -> Maybe Version   -- ^ optional GHC version+                  -> m [FilePath]+hlsServerBinaries ver mghcVer = do+  Dirs {..}  <- getDirs+  liftIO $ handleIO (\_ -> pure []) $ findFiles+    binDir+    (makeRegexOpts+      compExtended+      execBlank+      ([s|^haskell-language-server-|]+        <> maybe [s|.*|] escapeVerRex mghcVer+        <> [s|~|]+        <> escapeVerRex ver+        <> E.encodeUtf8 (T.pack exeExt)+        <> [s|$|] :: ByteString+      )+    )++-- | Get all scripts for a hls version from the ~/.ghcup/hls/<ver>/bin directory, if any.+-- Returns the full path.+hlsInternalServerScripts :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m)+                          => Version+                          -> Maybe Version   -- ^ optional GHC version+                          -> m [FilePath]+hlsInternalServerScripts ver mghcVer = do+  dir <- ghcupHLSDir ver+  let bdir = fromGHCupPath dir </> "bin"+  fmap (bdir </>) . filter (\f -> maybe True (\gv -> ("-" <> T.unpack (prettyVer gv)) `isSuffixOf` f) mghcVer)+    <$> liftIO (listDirectoryFiles bdir)++-- | Get all binaries for a hls version from the ~/.ghcup/hls/<ver>/lib/haskell-language-server-<ver>/bin directory, if any.+-- Returns the full path.+hlsInternalServerBinaries :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m, MonadFail m)+                          => Version+                          -> Maybe Version   -- ^ optional GHC version+                          -> m [FilePath]+hlsInternalServerBinaries ver mghcVer = do+  dir <- fromGHCupPath <$> ghcupHLSDir ver+  let regex = makeRegexOpts compExtended execBlank ([s|^haskell-language-server-.*$|] :: ByteString)+  (Just bdir) <- fmap headMay $ liftIO $ expandFilePath [Left (dir </> "lib"), Right regex, Left "bin"]+  fmap (bdir </>) . filter (\f -> maybe True (\gv -> ("-" <> T.unpack (prettyVer gv)) `isSuffixOf` f) mghcVer)+    <$> liftIO (listDirectoryFiles bdir)++-- | Get all libraries for a hls version from the ~/.ghcup/hls/<ver>/lib/haskell-language-server-<ver>/lib/<ghc-ver>/+-- directory, if any.+-- Returns the full path.+hlsInternalServerLibs :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m, MonadFail m)+                      => Version+                      -> Version   -- ^ GHC version+                      -> m [FilePath]+hlsInternalServerLibs ver ghcVer = do+  dir <- fromGHCupPath <$> ghcupHLSDir ver+  let regex = makeRegexOpts compExtended execBlank ([s|^haskell-language-server-.*$|] :: ByteString)+  (Just bdir) <- fmap headMay $ liftIO $ expandFilePath [Left (dir </> "lib"), Right regex, Left ("lib" </> T.unpack (prettyVer ghcVer))]+  fmap (bdir </>) <$> liftIO (listDirectoryFiles bdir)+++-- | Get the wrapper binary for an hls version, if any.+hlsWrapperBinary :: (MonadReader env m, HasDirs env, MonadThrow m, MonadIO m)+                 => Version+                 -> m (Maybe FilePath)+hlsWrapperBinary ver = do+  Dirs {..}  <- getDirs+  wrapper <- liftIO $ handleIO (\_ -> pure []) $ findFiles+    binDir+    (makeRegexOpts+      compExtended+      execBlank+      ([s|^haskell-language-server-wrapper-|] <> escapeVerRex ver <> E.encodeUtf8 (T.pack exeExt) <> [s|$|] :: ByteString+      )+    )+  case wrapper of+    []  -> pure Nothing+    [x] -> pure $ Just x+    _   -> throwM $ UnexpectedListLength+      "There were multiple hls wrapper binaries for a single version"+++-- | Get all binaries for an hls version, if any.+hlsAllBinaries :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m) => Version -> m [FilePath]+hlsAllBinaries ver = do+  hls'     <- hlsServerBinaries ver Nothing+  wrapper <- hlsWrapperBinary ver+  pure (maybeToList wrapper ++ hls')++++++    -------------+    --[ Other ]--+    -------------+++-- | Usually @~\/.ghcup\/ghc\/\<ver\>\/bin\/@+ghcInternalBinDir :: (MonadReader env m, HasDirs env, MonadThrow m, MonadFail m, MonadIO m)+                  => TargetVersion+                  -> m FilePath+ghcInternalBinDir ver = do+  ghcdir <- fromGHCupPath <$> ghcupGHCDir ver+  pure (ghcdir </> "bin")+++-- | Get tool files from @~\/.ghcup\/ghc\/\<ver\>\/bin\/\*@+-- while ignoring @*-\<ver\>@ symlinks and accounting for cross triple prefix.+--+-- Returns unversioned relative files without extension, e.g.:+--+--   - @["hsc2hs","haddock","hpc","runhaskell","ghc","ghc-pkg","ghci","runghc","hp2ps"]@+ghcToolFiles :: (MonadReader env m, HasDirs env, HasLog env, MonadThrow m, MonadFail m, MonadIO m)+             => TargetVersion+             -> Excepts '[NotInstalled] m [FilePath]+ghcToolFiles ver = do+  bindir <- ghcInternalBinDir ver+  logDebug2 $ "(ghcToolFiles) bindir: " <> T.pack bindir++  -- fail if ghc is not installed+  whenM (fmap not $ ghcInstalled ver)+        (throwE (NotInstalled ghc ver))++  files <- liftIO (listDirectoryFiles bindir >>= filterM (doesFileExist . (bindir </>)))+  logDebug2 $ "(ghcToolFiles) files: " <> T.pack (show files)+  let unique = getUniqueTools . groupToolFiles . fmap (dropSuffix exeExt) $ files+  logDebug2 $ "(ghcToolFiles) unique: " <> T.pack (show unique)+  pure unique++ where++  groupToolFiles :: [FilePath] -> [[(FilePath, String)]]+  groupToolFiles = groupBy (\(a, _) (b, _) -> a == b) . fmap (splitOnPVP "-")++  getUniqueTools :: [[(FilePath, String)]] -> [String]+  getUniqueTools = filter (isNotAnyInfix blackListedTools) . nub . fmap fst . concatMap (filter ((== "") . snd))++  blackListedTools :: [String]+  blackListedTools = ["haddock-ghc"]++  isNotAnyInfix :: [String] -> String -> Bool+  isNotAnyInfix xs t = foldr (\a b -> not (a `isInfixOf` t) && b) True xs+++++-- | For ghc without arch triple, this is:+--+--    - ghc+--+-- For ghc with arch triple:+--+--    - <triple>-ghc (e.g. arm-linux-gnueabihf-ghc)+ghcBinaryName :: TargetVersion -> String+ghcBinaryName (TargetVersion (Just t) _) = T.unpack (t <> "-ghc" <> T.pack exeExt)+ghcBinaryName (TargetVersion Nothing  _) = T.unpack ("ghc" <> T.pack exeExt)++++-- | Warn if the installed and set HLS is not compatible with the installed and+-- set GHC version.+warnAboutHlsCompatibility :: ( MonadReader env m+                             , HasDirs env+                             , HasLog env+                             , MonadIOish m+                             )+                          => m ()+warnAboutHlsCompatibility = do+  supportedGHC <- hlsGHCVersions+  currentGHC   <- fmap _tvVersion <$> ghcSet Nothing+  currentHLS   <- hlsSet+  Warnings.warnAboutHlsCompatibility currentHLS currentGHC supportedGHC
− lib/GHCup/List.hs
@@ -1,439 +0,0 @@-{-# LANGUAGE CPP                   #-}-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE FlexibleInstances     #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedStrings     #-}--{-|-Module      : GHCup.List-Description : Listing versions and tools-Copyright   : (c) Julian Ospald, 2020-License     : LGPL-3.0-Maintainer  : hasufell@hasufell.de-Stability   : experimental-Portability : portable--}-module GHCup.List where--import           GHCup.Download-import           GHCup.Errors-import           GHCup.Types-import           GHCup.Types.JSON               ( )-import           GHCup.Types.Optics-import           GHCup.Utils-import           GHCup.Prelude.Logger-import           GHCup.Version--import           Control.Applicative-import           Control.Exception.Safe-import           Control.Monad-#if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )-#endif-import           Control.Monad.Reader-import           Data.Either-import           Data.List-import           Data.Maybe-import           Data.Text                      ( Text )-import           Data.Time.Calendar             ( Day )-import           Data.Versions                hiding ( patch )-import           Data.Variant.Excepts-import           Optics-import           Prelude                 hiding ( abs-                                                , writeFile-                                                )--import qualified Data.Map.Strict               as Map-import qualified Data.Text                     as T-----------    -------------------    --[ List tools ]---    ----------------------- | Filter data type for 'listVersions'.-data ListCriteria = ListInstalled  Bool-                  | ListSet        Bool-                  | ListAvailable  Bool-                  deriving (Eq, Show)---- | A list result describes a single tool version--- and various of its properties.-data ListResult = ListResult-  { lTool      :: Tool-  , lVer       :: Version-  , lCross     :: Maybe Text -- ^ currently only for GHC-  , lTag       :: [Tag]-  , lInstalled :: Bool-  , lSet       :: Bool -- ^ currently active version-  , lStray     :: Bool -- ^ not in download info-  , lNoBindist :: Bool -- ^ whether the version is available for this platform/arch-  , hlsPowered :: Bool-  , lReleaseDay :: Maybe Day-  }-  deriving (Eq, Ord, Show)----- | Extract all available tool versions and their tags.-availableToolVersions :: GHCupDownloads -> Tool -> Map.Map GHCTargetVersion VersionInfo-availableToolVersions av tool = view-  (at tool % non Map.empty)-  av----- | List all versions from the download info, as well as stray--- versions.-listVersions :: ( MonadCatch m-                             , HasLog env-                             , MonadThrow m-                             , HasLog env-                             , MonadIO m-                             , MonadReader env m-                             , HasDirs env-                             , HasPlatformReq env-                             , HasGHCupInfo env-                             )-                          => Maybe Tool-                          -> [ListCriteria]-                          -> Bool-                          -> Bool-                          -> (Maybe Day, Maybe Day)-                          -> m [ListResult]-listVersions lt' criteria hideOld showNightly days = do-  -- some annoying work to avoid too much repeated IO-  cSet <- cabalSet-  cabals <- getInstalledCabals-  hlsSet' <- hlsSet-  hlses <- getInstalledHLSs-  sSet <- stackSet-  stacks <- getInstalledStacks-  hlsGHCVs <- fmap mkTVer <$> hlsGHCVersions--  go lt' hlsGHCVs cSet cabals hlsSet' hlses sSet stacks- where-  go lt hlsGHCVs cSet cabals hlsSet' hlses sSet stacks = do-    case lt of-      Just t -> do-        GHCupInfo { _ghcupDownloads = dls } <- getGHCupInfo-        -- get versions from GHCupDownloads-        let avTools = availableToolVersions dls t-        lr <- filter' <$> forM (Map.toList avTools) (toListResult t hlsGHCVs cSet cabals hlsSet' hlses sSet stacks)--        case t of-          GHC -> do-            slr <- strayGHCs avTools-            pure (sort (slr ++ lr))-          Cabal -> do-            slr <- strayCabals (Map.mapKeys _tvVersion avTools) cSet cabals-            pure (sort (slr ++ lr))-          HLS -> do-            slr <- strayHLS (Map.mapKeys _tvVersion avTools) hlsSet' hlses-            pure (sort (slr ++ lr))-          Stack -> do-            slr <- strayStacks (Map.mapKeys _tvVersion avTools) sSet stacks-            pure (sort (slr ++ lr))-          GHCup -> do-            let cg = maybeToList $ currentGHCup avTools-            pure (sort (cg ++ lr))-      Nothing -> do-        ghcvers   <- go (Just GHC) hlsGHCVs cSet cabals hlsSet' hlses sSet stacks-        cabalvers <- go (Just Cabal) hlsGHCVs cSet cabals hlsSet' hlses sSet stacks-        hlsvers   <- go (Just HLS) hlsGHCVs cSet cabals hlsSet' hlses sSet stacks-        ghcupvers <- go (Just GHCup) hlsGHCVs cSet cabals hlsSet' hlses sSet stacks-        stackvers <- go (Just Stack) hlsGHCVs cSet cabals hlsSet' hlses sSet stacks-        pure (ghcvers <> cabalvers <> hlsvers <> stackvers <> ghcupvers)-  strayGHCs :: ( MonadCatch m-               , MonadReader env m-               , HasDirs env-               , MonadThrow m-               , HasLog env-               , MonadIO m-               )-            => Map.Map GHCTargetVersion VersionInfo-            -> m [ListResult]-  strayGHCs avTools = do-    ghcs <- getInstalledGHCs-    fmap catMaybes $ forM ghcs $ \case-      Right tver@GHCTargetVersion{ .. } -> do-        case Map.lookup tver avTools of-          Just _  -> pure Nothing-          Nothing -> do-            lSet    <- fmap (maybe False (\(GHCTargetVersion _ v ) -> v == _tvVersion)) $ ghcSet _tvTarget-            hlsPowered <- fmap (elem _tvVersion) hlsGHCVersions-            pure $ Just $ ListResult-              { lTool      = GHC-              , lVer       = _tvVersion-              , lCross     = _tvTarget-              , lTag       = []-              , lInstalled = True-              , lStray     = isNothing (Map.lookup tver avTools)-              , lNoBindist = False-              , lReleaseDay = Nothing-              , ..-              }-      Left e -> do-        logWarn-          $ "Could not parse version of stray directory " <> T.pack e-        pure Nothing--  strayCabals :: ( MonadReader env m-                 , HasDirs env-                 , MonadCatch m-                 , MonadThrow m-                 , HasLog env-                 , MonadIO m-                 )-            => Map.Map Version VersionInfo-            -> Maybe Version-            -> [Either FilePath Version]-            -> m [ListResult]-  strayCabals avTools cSet cabals = do-    fmap catMaybes $ forM cabals $ \case-      Right ver ->-        case Map.lookup ver avTools of-          Just _  -> pure Nothing-          Nothing -> do-            let lSet = cSet == Just ver-            pure $ Just $ ListResult-              { lTool      = Cabal-              , lVer       = ver-              , lCross     = Nothing-              , lTag       = []-              , lInstalled = True-              , lStray     = isNothing (Map.lookup ver avTools)-              , lNoBindist = False-              , hlsPowered = False-              , lReleaseDay = Nothing-              , ..-              }-      Left e -> do-        logWarn-          $ "Could not parse version of stray directory " <> T.pack e-        pure Nothing--  strayHLS :: ( MonadReader env m-              , HasDirs env-              , MonadCatch m-              , MonadThrow m-              , HasLog env-              , MonadIO m)-           => Map.Map Version VersionInfo-           -> Maybe Version-           -> [Either FilePath Version]-           -> m [ListResult]-  strayHLS avTools hlsSet' hlss = do-    fmap catMaybes $ forM hlss $ \case-      Right ver ->-        case Map.lookup ver avTools of-          Just _  -> pure Nothing-          Nothing -> do-            let lSet = hlsSet' == Just ver-            pure $ Just $ ListResult-              { lTool      = HLS-              , lVer       = ver-              , lCross     = Nothing-              , lTag       = []-              , lInstalled = True-              , lStray     = isNothing (Map.lookup ver avTools)-              , lNoBindist = False-              , hlsPowered = False-              , lReleaseDay = Nothing-              , ..-              }-      Left e -> do-        logWarn-          $ "Could not parse version of stray directory " <> T.pack e-        pure Nothing--  strayStacks :: ( MonadReader env m-                 , HasDirs env-                 , MonadCatch m-                 , MonadThrow m-                 , HasLog env-                 , MonadIO m-                 )-              => Map.Map Version VersionInfo-              -> Maybe Version-              -> [Either FilePath Version]-              -> m [ListResult]-  strayStacks avTools stackSet' stacks = do-    fmap catMaybes $ forM stacks $ \case-      Right ver ->-        case Map.lookup ver avTools of-          Just _  -> pure Nothing-          Nothing -> do-            let lSet = stackSet' == Just ver-            pure $ Just $ ListResult-              { lTool      = Stack-              , lVer       = ver-              , lCross     = Nothing-              , lTag       = []-              , lInstalled = True-              , lStray     = isNothing (Map.lookup ver avTools)-              , lNoBindist = False-              , hlsPowered = False-              , lReleaseDay = Nothing-              , ..-              }-      Left e -> do-        logWarn-          $ "Could not parse version of stray directory " <> T.pack e-        pure Nothing--  currentGHCup :: Map.Map GHCTargetVersion VersionInfo -> Maybe ListResult-  currentGHCup av =-    let currentVer = mkTVer $ fromJust $ pvpToVersion ghcUpVer ""-        listVer    = Map.lookup currentVer av-        latestVer  = fst <$> headOf (getTagged Latest) av-        recommendedVer = fst <$> headOf (getTagged Latest) av-        isOld  = maybe True (> currentVer) latestVer && maybe True (> currentVer) recommendedVer-    in if | Map.member currentVer av -> Nothing-          | otherwise -> Just $ ListResult { lVer    = _tvVersion currentVer-                                           , lTag    = maybe (if isOld then [Old] else []) _viTags listVer-                                           , lCross  = Nothing-                                           , lTool   = GHCup-                                           , lStray  = isNothing listVer-                                           , lSet    = True-                                           , lInstalled = True-                                           , lNoBindist = False-                                           , hlsPowered = False-                                           , lReleaseDay = Nothing-                                           }--  -- NOTE: this are not cross ones, because no bindists-  toListResult :: ( HasLog env-                  , MonadReader env m-                  , HasDirs env-                  , HasGHCupInfo env-                  , HasPlatformReq env-                  , MonadIO m-                  , MonadCatch m-                  )-               => Tool-               -> [GHCTargetVersion]-               -> Maybe Version-               -> [Either FilePath Version]-               -> Maybe Version-               -> [Either FilePath Version]-               -> Maybe Version-               -> [Either FilePath Version]-               -> (GHCTargetVersion, VersionInfo)-               -> m ListResult-  toListResult t hlsGHCVs cSet cabals hlsSet' hlses stackSet' stacks (tver, VersionInfo{..}) = do-    let v = _tvVersion tver-    case t of-      GHC -> do-        dli <- fmap veitherToEither $ runE @'[NoDownload] $ getDownloadInfo' GHC tver-        let lNoBindist = isLeft dli-        let bTags = either (const []) (fromMaybe [] . _dlTag) dli-        lSet       <- fmap (== Just tver) $ ghcSet (_tvTarget tver)-        lInstalled <- ghcInstalled tver-        let hlsPowered = tver `elem` hlsGHCVs-        pure ListResult { lVer = _tvVersion tver-                        , lCross = _tvTarget tver-                        , lTag = _viTags <> bTags-                        , lTool = t-                        , lStray = False-                        , lReleaseDay = _viReleaseDay-                        , ..-                        }-      Cabal -> do-        dli <- fmap veitherToEither $ runE @'[NoDownload] $ getDownloadInfo Cabal v-        let lNoBindist = isLeft dli-        let bTags = either (const []) (fromMaybe [] . _dlTag) dli-        let lSet = cSet == Just v-        let lInstalled = elem v $ rights cabals-        pure ListResult { lVer    = v-                        , lCross  = Nothing-                        , lTag    = _viTags <> bTags-                        , lTool   = t-                        , lStray  = False-                        , hlsPowered = False-                        , lReleaseDay = _viReleaseDay-                        , ..-                        }-      GHCup -> do-        let lSet       = prettyPVP ghcUpVer == prettyVer v-        let lInstalled = lSet-        pure ListResult { lVer    = v-                        , lTag    = _viTags-                        , lCross  = Nothing-                        , lTool   = t-                        , lStray  = False-                        , lNoBindist = False-                        , hlsPowered = False-                        , lReleaseDay = _viReleaseDay-                        , ..-                        }-      HLS -> do-        dli <- fmap veitherToEither $ runE @'[NoDownload] $ getDownloadInfo HLS v-        let lNoBindist = isLeft dli-        let bTags = either (const []) (fromMaybe [] . _dlTag) dli-        let lSet = hlsSet' == Just v-        let lInstalled = elem v $ rights hlses-        pure ListResult { lVer    = v-                        , lCross  = Nothing-                        , lTag    = _viTags <> bTags-                        , lTool   = t-                        , lStray  = False-                        , hlsPowered = False-                        , lReleaseDay = _viReleaseDay-                        , ..-                        }-      Stack -> do-        dli <- fmap veitherToEither $ runE @'[NoDownload] $ getDownloadInfo Stack v-        let lNoBindist = isLeft dli-        let bTags = either (const []) (fromMaybe [] . _dlTag) dli-        let lSet = stackSet' == Just v-        let lInstalled = elem v $ rights stacks-        pure ListResult { lVer    = v-                        , lCross  = Nothing-                        , lTag    = _viTags <> bTags-                        , lTool   = t-                        , lStray  = False-                        , hlsPowered = False-                        , lReleaseDay = _viReleaseDay-                        , ..-                        }---  filter' :: [ListResult] -> [ListResult]-  filter' = filterNightly . filterOld . filter (\lr -> foldr (\a b -> fromCriteria a lr && b) True criteria) . filterDays--  filterDays :: [ListResult] -> [ListResult]-  filterDays lrs = case days of-                     (Nothing, Nothing)    -> lrs-                     (Just from, Just to') -> filter (\ListResult{..} -> maybe False (\d -> d >= from && d <= to') lReleaseDay) lrs-                     (Nothing, Just to')   -> filter (\ListResult{..} -> maybe False (<= to')                      lReleaseDay) lrs-                     (Just from, Nothing)  -> filter (\ListResult{..} -> maybe False (>= from)                     lReleaseDay) lrs--  fromCriteria :: ListCriteria -> ListResult -> Bool-  fromCriteria lc ListResult{..} = case lc of-    ListInstalled  b -> f b lInstalled-    ListSet        b -> f b lSet-    ListAvailable  b -> f b $ not lNoBindist-   where-    f b-      | b         = id-      | otherwise = not--  filterOld :: [ListResult] -> [ListResult]-  filterOld lr-    | hideOld   = filter (\ListResult {..} -> lInstalled || Old `notElem` lTag) lr-    | otherwise = lr--  filterNightly :: [ListResult] -> [ListResult]-  filterNightly lr-    | showNightly = lr-    | otherwise   = filter (\ListResult {..} -> lInstalled || (Nightly `notElem` lTag && LatestNightly `notElem` lTag)) lr-
lib/GHCup/PlanJson.hs view
@@ -1,8 +1,9 @@ module GHCup.PlanJson where -import Control.Monad (unless)+import GHCup.System.Directory++import Control.Monad    ( unless ) import System.FilePath-import System.Directory  findPlanJson     :: FilePath
− lib/GHCup/Platform.hs
@@ -1,374 +0,0 @@-{-# LANGUAGE CPP                   #-}-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE FlexibleInstances     #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE QuasiQuotes           #-}-{-# LANGUAGE TemplateHaskellQuotes #-}---{-|-Module      : GHCup.Platform-Description : Retrieving platform information-Copyright   : (c) Julian Ospald, 2020-License     : LGPL-3.0-Maintainer  : hasufell@hasufell.de-Stability   : experimental-Portability : portable--}-module GHCup.Platform where---import           GHCup.Errors-import           GHCup.Types-import           GHCup.Types.Optics-import           GHCup.Types.JSON               ( )-import           GHCup.Utils.Dirs-import           GHCup.Prelude-import           GHCup.Prelude.Logger-import           GHCup.Prelude.Process-import           GHCup.Prelude.String.QQ-import           GHCup.Prelude.Version.QQ-import           GHCup.Prelude.MegaParsec--#if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )-#endif-import           Control.Applicative-import           Control.Exception.Safe-import           Control.Monad-import           Control.Monad.Reader-import           Data.ByteString                ( ByteString )-import           Data.Foldable-import           Data.Maybe-import           Data.Text                      ( Text )-import           Data.Versions-import           Data.Variant.Excepts-import           Prelude                 hiding ( abs-                                                , readFile-                                                , writeFile-                                                )-import           System.Info-import           System.OsRelease as OSR-import           System.Exit-import           System.FilePath-import           Text.PrettyPrint.HughesPJClass ( prettyShow )-import           Text.Regex.Posix--import qualified Text.Megaparsec               as MP--import qualified Data.Text                     as T-import qualified Data.Text.IO                  as T-import           Data.Void-import qualified Data.List                     as L-----    ---------------------------    --[ Platform detection ]---    ------------------------------- | Get the full platform request, consisting of architecture, distro, ...-platformRequest :: (MonadReader env m, Alternative m, MonadFail m, HasLog env, MonadCatch m, MonadIO m)-                => Excepts-                     '[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound]-                     m-                     PlatformRequest-platformRequest = do-  (PlatformResult rp rv) <- liftE getPlatform-  ar                     <- lE getArchitecture-  pure $ PlatformRequest ar rp rv---getArchitecture :: Either NoCompatibleArch Architecture-getArchitecture = case arch of-  "x86_64"      -> Right A_64-  "i386"        -> Right A_32-  "powerpc"     -> Right A_PowerPC-  "powerpc64"   -> Right A_PowerPC64-  "powerpc64le" -> Right A_PowerPC64-  "sparc"       -> Right A_Sparc-  "sparc64"     -> Right A_Sparc64-  "arm"         -> Right A_ARM-  "aarch64"     -> Right A_ARM64-  what          -> Left (NoCompatibleArch what)---getPlatform :: (Alternative m, MonadReader env m, HasLog env, MonadCatch m, MonadIO m, MonadFail m)-            => Excepts-                 '[NoCompatiblePlatform, DistroNotFound]-                 m-                 PlatformResult-getPlatform = do-  pfr <- case os of-    "linux" -> do-      (distro, ver) <- liftE getLinuxDistro-      pure $ PlatformResult { _platform = Linux distro, _distroVersion = ver }-    "darwin" -> do-      ver <--        either (const Nothing) Just-          . versioning-          -- TODO: maybe do this somewhere else-          . decUTF8Safe'-        <$> getDarwinVersion-      pure $ PlatformResult { _platform = Darwin, _distroVersion = ver }-    "freebsd" -> do-      ver <--        either (const Nothing) Just . versioning . decUTF8Safe'-          <$> getFreeBSDVersion-      pure $ PlatformResult { _platform = FreeBSD, _distroVersion = ver }-    "openbsd" -> do-      ver <--        either (const Nothing) Just . versioning . decUTF8Safe'-          <$> getOpenBSDVersion-      pure $ PlatformResult { _platform = OpenBSD, _distroVersion = ver }-    "mingw32" -> pure PlatformResult { _platform = Windows, _distroVersion = Nothing }-    what -> throwE $ NoCompatiblePlatform what-  lift $ logDebug $ "Identified Platform as: " <> T.pack (prettyShow pfr)-  pure pfr- where-  getOpenBSDVersion = lift $ fmap _stdOut $ executeOut "uname" ["-r"] Nothing-  getFreeBSDVersion = lift $ fmap _stdOut $ executeOut "freebsd-version" [] Nothing-  getDarwinVersion = lift $ fmap _stdOut $ executeOut "sw_vers"-                                                        ["-productVersion"]-                                                        Nothing---getLinuxDistro :: (Alternative m, MonadCatch m, MonadIO m, MonadFail m)-               => Excepts '[DistroNotFound] m (LinuxDistro, Maybe Versioning)-getLinuxDistro = do-  -- TODO: don't do alternative on IO, because it hides bugs-  (name, mid, ver) <- handleIO (\_ -> throwE DistroNotFound) $ lift $ asum-    [ liftIO try_os_release-    , try_lsb_release_cmd-    , liftIO try_redhat_release-    , liftIO try_debian_version-    ]-  let hasWord xs = let f t = any (\x -> match (regex x) (T.unpack t)) xs-                   in f name || maybe False f mid-  let parsedVer = ver >>= either (const Nothing) Just . versioning-      distro    = if-        | hasWord ["debian"]  -> Debian-        | hasWord ["ubuntu"]  -> Ubuntu-        | hasWord ["linuxmint", "Linux Mint"] -> Mint-        | hasWord ["fedora"]  -> Fedora-        | hasWord ["centos"]  -> CentOS-        | hasWord ["Red Hat"] -> RedHat-        | hasWord ["alpine"]  -> Alpine-        | hasWord ["exherbo"] -> Exherbo-        | hasWord ["gentoo"]  -> Gentoo-        | hasWord ["opensuse", "suse"]  -> OpenSUSE-        | hasWord ["amazonlinux", "Amazon Linux"] -> AmazonLinux-        | hasWord ["rocky", "Rocky Linux"] -> Rocky-        -- https://github.com/void-linux/void-packages/blob/master/srcpkgs/base-files/files/os-release-        | hasWord ["void", "Void Linux"] -> Void-        | otherwise -> UnknownLinux-  pure (distro, parsedVer)- where-  regex x = makeRegexOpts compIgnoreCase execBlank ([s|\<|] ++ x ++ [s|\>|])--  lsb_release_cmd :: FilePath-  lsb_release_cmd = "lsb-release"-  redhat_release :: FilePath-  redhat_release = "/etc/redhat-release"-  debian_version :: FilePath-  debian_version = "/etc/debian_version"--  try_os_release :: IO (Text, Maybe Text, Maybe Text)-  try_os_release = do-    Just OsRelease{ name = name, version_id = version_id, OSR.id = id' } <--      fmap osRelease <$> parseOsRelease-    pure (T.pack name, Just (T.pack id'), fmap T.pack version_id)--  try_lsb_release_cmd :: (MonadFail m, MonadIO m)-                      => m (Text, Maybe Text, Maybe Text)-  try_lsb_release_cmd = do-    (Just _) <- liftIO $ findExecutable lsb_release_cmd-    name     <- fmap _stdOut $ executeOut lsb_release_cmd ["-si"] Nothing-    ver      <- fmap _stdOut $ executeOut lsb_release_cmd ["-sr"] Nothing-    pure (decUTF8Safe' name, Nothing, Just $ decUTF8Safe' ver)--  try_redhat_release :: IO (Text, Maybe Text, Maybe Text)-  try_redhat_release = do-    t <- T.readFile redhat_release-    let nameRegex n =-          makeRegexOpts compIgnoreCase-                        execBlank-                        ([s|\<|] <> fS n <> [s|\>|] :: ByteString) :: Regex-    let verRegex =-          makeRegexOpts compIgnoreCase-                        execBlank-                        ([s|\<([0-9])+(.([0-9])+)*\>|] :: ByteString) :: Regex-    let nameRe n =-          fromEmpty . match (nameRegex n) $ T.unpack t :: Maybe String-        verRe = fromEmpty . match verRegex $ T.unpack t :: Maybe String-    (Just name) <- pure-      (nameRe "CentOS" <|> nameRe "Fedora" <|> nameRe "Red Hat")-    pure (T.pack name, Nothing, fmap T.pack verRe)-   where-    fromEmpty :: String -> Maybe String-    fromEmpty "" = Nothing-    fromEmpty s' = Just s'--  try_debian_version :: IO (Text, Maybe Text, Maybe Text)-  try_debian_version = do-    ver <- T.readFile debian_version-    pure (T.pack "debian", Just (T.pack "debian"), Just ver)---getStackGhcBuilds :: (MonadReader env m, HasLog env, MonadIO m)-                  => PlatformResult-                  -> Excepts '[ParseError, NoCompatiblePlatform, DistroNotFound, ProcessError] m [String]-getStackGhcBuilds PlatformResult{..} = do-    case _platform of-      Linux _ -> do-        -- Some systems don't have ldconfig in the PATH, so make sure to look in-        -- /sbin and /usr/sbin as well-        sbinEnv <- liftIO $ addToPath sbinDirs False-        ldConfig <- lift $ executeOut' "ldconfig" ["-p"] Nothing (Just sbinEnv)-        firstWords <- case ldConfig of-                        CapturedProcess ExitSuccess so _ ->-                          pure . mapMaybe (listToMaybe . T.words) . T.lines . T.pack . stripNewlineEnd . T.unpack . decUTF8Safe' $ so-                        CapturedProcess (ExitFailure _) _ _ ->-                          -- throwE $ NonZeroExit c "ldconfig" ["-p" ]-                          pure []-        let checkLib :: (MonadReader env m, HasLog env, MonadIO m) => String -> m Bool-            checkLib lib-              | libT `elem` firstWords = do-                  logDebug $ "Found shared library " <> libT <> " in 'ldconfig -p' output"-                  pure True-              | isWindows =-                  -- Cannot parse /usr/lib on Windows-                  pure False-              | otherwise = hasMatches lib usrLibDirs-              -- This is a workaround for the fact that libtinfo.so.x doesn't-              -- appear in the 'ldconfig -p' output on Arch or Slackware even-              -- when it exists. There doesn't seem to be an easy way to get the-              -- true list of directories to scan for shared libs, but this-              -- works for our particular cases.-             where-              libT = T.pack lib--            hasMatches :: (MonadReader env m, HasLog env, MonadIO m) => String -> [FilePath] -> m Bool-            hasMatches lib dirs = do-              matches <- filterM (liftIO . doesFileExist . (</> lib)) dirs-              case matches of-                [] -> logDebug ("Did not find shared library " <> libT) >> pure False-                (path:_) -> logDebug ("Found shared library " <> libT <> " in " <> T.pack path) >> pure True-             where-              libT = T.pack lib--            getLibc6Version :: MonadIO m-                            => Excepts '[ParseError, ProcessError] m Version-            getLibc6Version = do-              CapturedProcess{..} <- lift $ executeOut "ldd" ["--version"] Nothing-              case _exitCode of-                ExitSuccess -> either (throwE . ParseError . show) pure-                                 . MP.parse lddVersion "" . T.pack . stripNewlineEnd . T.unpack . decUTF8Safe' $ _stdOut-                ExitFailure c -> throwE $ NonZeroExit c "ldd" ["--version" ]--            -- Assumes the first line of ldd has the format:-            ---            -- ldd (...) nn.nn-            ---            -- where nn.nn corresponds to the version of libc6.-            lddVersion :: MP.Parsec Void Text Version-            lddVersion = do-              skipWhile (/= ')')-              skip (== ')')-              skipSpace-              version'--        hasMusl <- hasMatches relFileLibcMuslx86_64So1 libDirs-        mLibc6Version <- veitherToEither <$> runE getLibc6Version-        case mLibc6Version of-          Right libc6Version -> logDebug $ "Found shared library libc6 in version: " <> prettyVer libc6Version-          Left _ -> logDebug "Did not find a version of shared library libc6."-        let hasLibc6_2_32 = either (const False) (>= [vver|2.32|]) mLibc6Version-        hastinfo5 <- checkLib relFileLibtinfoSo5-        hastinfo6 <- checkLib relFileLibtinfoSo6-        hasncurses6 <- checkLib relFileLibncurseswSo6-        hasgmp5 <- checkLib relFileLibgmpSo10-        hasgmp4 <- checkLib relFileLibgmpSo3-        let libComponents = if hasMusl-              then-                [ ["musl"] ]-              else-                concat-                  [ if hastinfo6 && hasgmp5-                    then-                      if hasLibc6_2_32-                      then [["tinfo6"]]-                      else [["tinfo6-libc6-pre232"]]-                    else [[]]-                  , [ [] | hastinfo5 && hasgmp5 ]-                  , [ ["ncurses6"] | hasncurses6 && hasgmp5 ]-                  , [ ["gmp4"] | hasgmp4 ]-                  ]-        pure $ map-          (\c -> case c of-            [] -> []-            _ -> L.intercalate "-" c)-          libComponents-      OpenBSD -> pure []-      FreeBSD ->-        case _distroVersion of-          Just fVer-            | fVer >= [vers|12|] -> pure []-          _ -> pure ["ino64"]-      Darwin  -> pure []-      Windows -> pure []- where--  relFileLibcMuslx86_64So1 :: FilePath-  relFileLibcMuslx86_64So1 = "libc.musl-x86_64.so.1"-  libDirs :: [FilePath]-  libDirs = ["/lib", "/lib64"]-  usrLibDirs :: [FilePath]-  usrLibDirs = ["/usr/lib", "/usr/lib64"]-  sbinDirs :: [FilePath]-  sbinDirs = ["/sbin", "/usr/sbin"]-  relFileLibtinfoSo5 :: FilePath-  relFileLibtinfoSo5 = "libtinfo.so.5"-  relFileLibtinfoSo6 :: FilePath-  relFileLibtinfoSo6 = "libtinfo.so.6"-  relFileLibncurseswSo6 :: FilePath-  relFileLibncurseswSo6 = "libncursesw.so.6"-  relFileLibgmpSo10 :: FilePath-  relFileLibgmpSo10 = "libgmp.so.10"-  relFileLibgmpSo3 :: FilePath-  relFileLibgmpSo3 = "libgmp.so.3"--getStackOSKey :: Monad m => PlatformRequest -> Excepts '[UnsupportedSetupCombo] m String-getStackOSKey PlatformRequest { .. } =-  case (_rArch, _rPlatform) of-    (A_32   , Linux _) -> pure "linux32"-    (A_64   , Linux _) -> pure "linux64"-    (A_32   , Darwin ) -> pure "macosx"-    (A_64   , Darwin ) -> pure "macosx"-    (A_32   , FreeBSD) -> pure "freebsd32"-    (A_64   , FreeBSD) -> pure "freebsd64"-    (A_32   , OpenBSD) -> pure "openbsd32"-    (A_64   , OpenBSD) -> pure "openbsd64"-    (A_32   , Windows) -> pure "windows32"-    (A_64   , Windows) -> pure "windows64"-    (A_ARM  , Linux _) -> pure "linux-armv7"-    (A_ARM64, Linux _) -> pure "linux-aarch64"-    (A_Sparc, Linux _) -> pure "linux-sparc"-    (A_ARM64, Darwin ) -> pure "macosx-aarch64"-    (A_ARM64, FreeBSD) -> pure "freebsd-aarch64"-    (A_ARM64, OpenBSD) -> pure "openbsd-aarch64"-    (arch', os') -> throwE $ UnsupportedSetupCombo arch' os'--getStackPlatformKey :: (MonadReader env m, MonadFail m, HasLog env, MonadCatch m, MonadIO m)-                    => PlatformRequest-                    -> Excepts '[UnsupportedSetupCombo, ParseError, NoCompatiblePlatform, NoCompatibleArch, DistroNotFound, ProcessError] m [String]-getStackPlatformKey pfreq@PlatformRequest{..} = do-  osKey <- liftE  $ getStackOSKey pfreq-  builds <- liftE $ getStackGhcBuilds (PlatformResult _rPlatform _rVersion)-  let builds' = (\build -> if null build then osKey else osKey <> "-" <> build) <$> builds-  logDebug $ "Potential GHC builds: " <> mconcat (L.intersperse ", " $ fmap T.pack builds')-  pure builds'-
lib/GHCup/Prelude.hs view
@@ -1,10 +1,10 @@-{-# LANGUAGE CPP                 #-}-{-# LANGUAGE DataKinds           #-}-{-# LANGUAGE FlexibleContexts    #-}-{-# LANGUAGE FlexibleInstances   #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies        #-}-{-# LANGUAGE TypeOperators       #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}  {-| Module      : GHCup.Prelude@@ -20,18 +20,26 @@ module GHCup.Prelude   (module GHCup.Prelude,    module GHCup.Prelude.Internal,+   module GHCup.Prelude.JSON,+   module GHCup.Prelude.File,+   module GHCup.Prelude.Logger,+   module GHCup.Prelude.Version, #if defined(IS_WINDOWS)-   module GHCup.Prelude.Windows+   module GHCup.Prelude.Windows, #else-   module GHCup.Prelude.Posix+   module GHCup.Prelude.Posix, #endif   ) where -import           GHCup.Errors-import           GHCup.Prelude.Internal-import           GHCup.Types.Optics   (HasLog)-import           GHCup.Prelude.Logger (logWarn)+import GHCup.Errors+import GHCup.Prelude.File+import GHCup.Prelude.Internal+import GHCup.Prelude.JSON+import GHCup.Prelude.Logger+import GHCup.Prelude.Version+import GHCup.Types            ( EnvUnion (..) )+import GHCup.Types.Optics     ( HasLog ) #if defined(IS_WINDOWS) import GHCup.Prelude.Windows #else@@ -40,13 +48,13 @@  import           Control.Monad.IO.Class import           Control.Monad.Reader+import           Data.List                      ( intercalate )+import qualified Data.Map.Strict                as Map+import qualified Data.Text                      as T import           Data.Variant.Excepts-import           Text.PrettyPrint.HughesPJClass ( Pretty )-import qualified Data.Text                     as T-import System.Environment (getEnvironment)-import qualified Data.Map.Strict               as Map-import System.FilePath-import Data.List (intercalate)+import           System.Environment             ( getEnvironment )+import           System.FilePath+import           Text.PrettyPrint.HughesPJClass ( Pretty, prettyShow )   @@ -59,6 +67,8 @@                              , Monad m) => Excepts es m () -> Excepts '[] m () catchWarn = catchAllE @_ @es (\v -> lift $ logWarn (T.pack . prettyHFError $ v)) +prettyText :: Pretty a => a -> T.Text+prettyText = T.pack . prettyShow  runBothE' :: forall e m a b .              ( Monad m@@ -81,6 +91,14 @@       (_       , VLeft e ) -> throwSomeE e       (VRight _, VRight _) -> pure () +augmentEnvironment :: [(String, String)] -> EnvUnion -> IO [(String, String)]+augmentEnvironment (Map.fromList -> addEnv) PreferSpec = do+ cEnv <- Map.fromList <$> getEnvironment+ pure (Map.toList $ Map.union addEnv cEnv)+augmentEnvironment (Map.fromList -> addEnv) PreferSystem = do+ cEnv <- Map.fromList <$> getEnvironment+ pure (Map.toList $ Map.union cEnv addEnv)+augmentEnvironment addEnv OnlySpec = pure addEnv  addToPath :: [FilePath]           -> Bool         -- ^ if False will prepend
lib/GHCup/Prelude/Attoparsec.hs view
@@ -1,5 +1,5 @@-{-# LANGUAGE CPP                  #-}-{-# LANGUAGE OverloadedStrings    #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}  {-| Module      : GHCup.Utils.Attoparsec@@ -12,15 +12,15 @@ -} module GHCup.Prelude.Attoparsec where -import           Control.Applicative+import Control.Applicative #if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )+import Control.Monad.Fail ( MonadFail ) #endif-import           Data.ByteString (ByteString)-import           Data.ByteString.Internal (w2c)-import           Data.Functor+import Data.ByteString          ( ByteString )+import Data.ByteString.Internal ( w2c )+import Data.Functor -import           Data.Attoparsec.ByteString as AP+import Data.Attoparsec.ByteString as AP   
lib/GHCup/Prelude/File.hs view
@@ -1,20 +1,22 @@-{-# LANGUAGE CPP                 #-}-{-# LANGUAGE BangPatterns        #-}-{-# LANGUAGE DataKinds           #-}-{-# LANGUAGE FlexibleContexts    #-}-{-# LANGUAGE FlexibleInstances   #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE OverloadedStrings   #-}-{-# LANGUAGE TypeFamilies        #-}-{-# LANGUAGE TypeOperators       #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}  module GHCup.Prelude.File (   mergeFileTree,   copyFileE,   findFilesDeep,+  getFilesDeep,   getDirectoryContentsRecursive,   getDirectoryContentsRecursiveUnsafe,   recordedInstallationFile,+  recordedInstallationSpecFile,+  recordedSetVersionFile,   module GHCup.Prelude.File.Search,    chmod_755,@@ -44,10 +46,10 @@   createLink ) where -import GHCup.Utils.Dirs-import GHCup.Prelude.Logger.Internal (logInfo, logDebug)-import GHCup.Prelude.Internal import GHCup.Prelude.File.Search+import GHCup.Prelude.Internal+import GHCup.Prelude.Logger.Internal ( logDebug, logDebug2 )+import GHCup.Query.GHCupDirs #if IS_WINDOWS import GHCup.Prelude.File.Windows import GHCup.Prelude.Windows@@ -55,26 +57,25 @@ import GHCup.Prelude.File.Posix import GHCup.Prelude.Posix #endif-import           GHCup.Errors-import           GHCup.Types-import           GHCup.Types.Optics+import GHCup.Errors+import GHCup.System.Directory+import GHCup.Types+import GHCup.Types.Optics -import           Text.Regex.Posix import           Conduit-import qualified Data.Conduit.Combinators as C import           Control.Exception.Safe import           Control.Monad.Reader import           Data.ByteString                ( ByteString )+import qualified Data.Conduit.Combinators       as C import           Data.Variant.Excepts import           System.FilePath-import           Text.PrettyPrint.HughesPJClass (prettyShow)+import           Text.PrettyPrint.HughesPJClass ( prettyShow )+import           Text.Regex.Posix -import qualified Data.Text                     as T-import Control.DeepSeq (force)-import Control.Exception (evaluate)-import GHC.IO.Exception-import System.IO.Error-import Control.Monad (when, forM_, filterM)+import           Control.Monad     ( filterM, forM_, when, unless )+import qualified Data.Text         as T+import           GHC.IO.Exception+import           System.IO.Error   -- | Merge one file tree to another given a copy operation.@@ -95,20 +96,21 @@               => GHCupPath                       -- ^ source base directory from which to install findFiles               -> InstallDirResolved              -- ^ destination base dir               -> Tool-              -> GHCTargetVersion+              -> TargetVersion               -> (FilePath -> FilePath -> m ())  -- ^ file copy operation+              -> Bool                            -- ^ whether to abort if the DB file already exists               -> Excepts '[MergeFileTreeError] m ()-mergeFileTree _ (GHCupBinDir fp) _ _ _ =+mergeFileTree _ (GHCupBinDir fp) _ _ _ _ =   throwIO $ userError ("mergeFileTree: internal error, called on " <> fp)-mergeFileTree sourceBase destBase tool v' copyOp = do-  lift $ logInfo $ "Merging file tree from \""+mergeFileTree sourceBase destBase tool v' copyOp append = do+  lift $ logDebug $ "Merging file tree from \""        <> T.pack (fromGHCupPath sourceBase)        <> "\" to \""        <> T.pack (fromInstallDir destBase)        <> "\""   recFile <- recordedInstallationFile tool v' -  wrapInExcepts $ do+  handleIO (\e -> throwE $ MergeFileTreeErrorPreCondition e (fromGHCupPath sourceBase) (fromInstallDir destBase)) $ do     -- These checks are not atomic, but we perform them to have     -- the opportunity to abort before copying has started.     --@@ -118,37 +120,19 @@      -- we only record for non-isolated installs     when (isSafeDir destBase) $ do-      whenM (liftIO $ doesFileExist recFile)+      whenM (fmap (&& not append) $ liftIO $ doesFileExist recFile)         $ throwIO $ userError ("mergeFileTree: DB file " <> recFile <> " already exists!")       liftIO $ createDirectoryIfMissing True (takeDirectory recFile)    -- we want the cleanup action to leak through in case of exception-  onE_ (cleanupOnPartialInstall recFile) $ wrapInExcepts $ do-    logDebug "Starting merge"+  logDebug "Starting merge"+  handleIO (\e -> throwE $ MergeFileTreeError e (fromInstallDir destBase) tool v') $     lift $ runConduitRes $ getDirectoryContentsRecursive sourceBase .| C.mapM_ (\f -> do       lift $ copy f-      logDebug $ T.pack "Recording installed file: " <> T.pack f+      logDebug2 $ T.pack "Recording installed file: " <> T.pack f       recordInstalledFile f recFile)   where-  wrapInExcepts = handleIO (\e -> throwE $ MergeFileTreeError e (fromGHCupPath sourceBase) (fromInstallDir destBase))--  cleanupOnPartialInstall recFile = when (isSafeDir destBase) $ do-    (force -> !l) <- hideErrorDef [NoSuchThing] [] $ lines <$> liftIO-      (readFile recFile >>= evaluate)-    logDebug "Deleting recorded files due to partial install"-    forM_ l $ \f -> do-      let dest = fromInstallDir destBase </> dropDrive f-      logDebug $ "rm -f " <> T.pack f-      hideError NoSuchThing $ rmFile dest-      pure ()-    logDebug $ "rm -f " <> T.pack recFile-    hideError NoSuchThing $ rmFile recFile-    logDebug $ "rm -f " <> T.pack (fromInstallDir destBase)-    hideError UnsatisfiedConstraints $ hideError NoSuchThing $-      removeEmptyDirsRecursive (fromInstallDir destBase)--   recordInstalledFile f recFile = when (isSafeDir destBase) $     liftIO $ appendFile recFile (f <> "\n") @@ -194,17 +178,46 @@ findFilesDeep path regex =   runResourceT $ sourceToList $ getDirectoryContentsRecursive path .| C.filter (match regex) +getFilesDeep :: GHCupPath -> IO [FilePath]+getFilesDeep path =+  runResourceT $ sourceToList $ getDirectoryContentsRecursive path + recordedInstallationFile :: ( MonadReader env m                             , HasDirs env+                            , MonadIO m                             )                          => Tool-                         -> GHCTargetVersion+                         -> TargetVersion                          -> m FilePath recordedInstallationFile t v' = do   Dirs {..}  <- getDirs   pure (fromGHCupPath dbDir </> prettyShow t </> T.unpack (tVerToText v')) +recordedInstallationSpecFile :: ( MonadReader env m+                                , HasDirs env+                                )+                             => Tool+                             -> TargetVersion+                             -> m FilePath+recordedInstallationSpecFile t v' = do+  Dirs {..}  <- getDirs+  pure (fromGHCupPath dbDir </> prettyShow t </> T.unpack (tVerToText v') <.> "spec")++recordedSetVersionFile ::+  ( MonadReader env m+  , HasDirs env+  )+  => Tool+  -> Maybe T.Text+  -> m FilePath+recordedSetVersionFile t Nothing = do+  Dirs {..}  <- getDirs+  pure (fromGHCupPath dbDir </> prettyShow t </> "set")+recordedSetVersionFile t (Just target) = do+  Dirs {..}  <- getDirs+  pure (fromGHCupPath dbDir </> prettyShow t </> T.unpack target <.> "set")+ removeDirIfEmptyOrIsSymlink :: (MonadMask m, MonadIO m, MonadCatch m) => FilePath -> m () removeDirIfEmptyOrIsSymlink filepath =   hideError UnsatisfiedConstraints $@@ -242,14 +255,13 @@  where   isSymlinkDir e = do     ft <- pathIsSymbolicLink p-    case ft of-      True -> do+    if ft+    then+      do         rp <- canonicalizePath p         rft <- doesDirectoryExist rp-        case rft of-          True -> pure ()-          _ -> throwIO e-      _ -> throwIO e+        unless rft $ throwIO e+    else throwIO e   -- https://github.com/haskell/directory/issues/110
lib/GHCup/Prelude/File/Posix.hs view
@@ -1,8 +1,9 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE DataKinds  #-}-{-# LANGUAGE MultiWayIf  #-} {-# LANGUAGE CApiFFI #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}  {-| Module      : GHCup.Utils.File.Posix@@ -15,28 +16,31 @@ -} module GHCup.Prelude.File.Posix where -import           Conduit-import           Control.Exception.Safe-import           Foreign.C.String-import           Foreign.C.Error-import           Foreign.C.Types-import           System.IO                      ( hClose, hSetBinaryMode )-import           System.IO.Error      hiding    ( catchIOError )-import           System.FilePath-import           System.Directory               ( removeFile, pathIsSymbolicLink, getSymbolicLinkTarget, doesPathExist )-import           System.Posix.Error             ( throwErrnoPathIfMinus1Retry )-import           System.Posix.Internals         ( withFilePath )-import           System.Posix.Files-import           System.Posix.Types+import Conduit+import Control.Exception.Safe+import Control.Monad (unless)+import Foreign.C.Error+import Foreign.C.String+import Foreign.C.Types+import System.Directory+    ( doesPathExist, getSymbolicLinkTarget, pathIsSymbolicLink, removeFile )+import System.FilePath+import System.IO              ( hClose, hSetBinaryMode )+import System.IO.Error        hiding ( catchIOError )+import System.Posix.Error     ( throwErrnoPathIfMinus1Retry )+import System.Posix.Files+import System.Posix.Internals ( withFilePath )+import System.Posix.Types  -import qualified System.Posix.Directory        as PD-import qualified System.Posix.Files            as PF-import qualified System.Posix.IO               as SPI-import qualified System.Posix as Posix-import qualified GHCup.Prelude.File.Posix.Foreign as FD-import GHCup.Prelude.File.Posix.Traversals-import GHC.IO.Exception (IOException(ioe_type), IOErrorType (..))+import           GHC.IO.Exception+    ( IOException (ioe_errno) )+import qualified GHCup.Prelude.File.Posix.Foreign    as FD+import           GHCup.Prelude.File.Posix.Traversals+import qualified System.Posix                        as Posix+import qualified System.Posix.Directory              as PD+import qualified System.Posix.Files                  as PF+import qualified System.Posix.IO                     as SPI  import qualified Data.Conduit.Combinators as C @@ -112,7 +116,15 @@           (handleIO (\e -> if                               -- if we copy from regular file to symlink, we need                               -- to delete the symlink-                              | ioe_type e == InvalidArgument+                              | ioe_errno e == Just ((\(Errno x) -> x)+#if defined(IS_FREEBSD)+-- https://man.freebsd.org/cgi/man.cgi?open(2)+                                                      eMLINK+#else+-- https://man7.org/linux/man-pages/man2/open.2.html+                                                      eLOOP+#endif+                                                    )                               , not fail' -> do                                  removeLink to                                  openFdHandle'@@ -221,10 +233,8 @@                 -> IO () recreateSymlink symsource newsym fail' = do   sympoint <- readSymbolicLink symsource-  case fail' of-    True  -> pure ()-    False ->-      handleIO (\e -> if doesNotExistErrorType  == ioeGetErrorType e then pure () else liftIO . ioError $ e) $ deleteFile newsym+  unless fail' $+    handleIO (\e -> if doesNotExistErrorType  == ioeGetErrorType e then pure () else liftIO . ioError $ e) $ deleteFile newsym   createSymbolicLink sympoint newsym  
lib/GHCup/Prelude/File/Search.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE DataKinds             #-}  module GHCup.Prelude.File.Search (   module GHCup.Prelude.File.Search@@ -9,31 +9,32 @@   , CapturedProcess(..)   ) where -import           GHCup.Prelude.Internal ((!?))-import           GHCup.Types(ProcessError(..), CapturedProcess(..))+import GHCup.Prelude.Internal ( (!?) )+import GHCup.Types            ( CapturedProcess (..), ProcessError (..) ) -import           Control.Monad (forM)-import           Control.Monad.Reader-import           Data.Maybe-import           Data.Text               ( Text )-import           Data.Void-import           GHC.IO.Exception-import           System.Directory hiding ( removeDirectory-                                         , removeDirectoryRecursive-                                         , removePathForcibly-                                         , findFiles-                                         , makeAbsolute-                                         )-import           System.FilePath-import           Text.Regex.Posix+import Control.Monad        ( forM )+import Control.Monad.Reader+import Data.Maybe+import Data.Text            ( Text )+import Data.Void+import GHC.IO.Exception+import System.Directory     hiding+    ( findFiles+    , makeAbsolute+    , removeDirectory+    , removeDirectoryRecursive+    , removePathForcibly+    )+import System.FilePath+import Text.Regex.Posix  -import qualified Data.Text                     as T-import qualified Text.Megaparsec               as MP-import Control.Exception.Safe (handleIO)-import System.Directory.Internal.Prelude (ioeGetErrorType)-import Data.Variant.Excepts (Excepts)-import GHCup.Errors (NotFoundInPATH(..))+import           Control.Exception.Safe            ( handleIO )+import qualified Data.Text                         as T+import           Data.Variant.Excepts              ( Excepts )+import           GHCup.Errors                      ( NotFoundInPATH (..) )+import           System.Directory.Internal.Prelude ( ioeGetErrorType )+import qualified Text.Megaparsec                   as MP   makeAbsolute :: MonadIO m => FilePath -> Excepts '[NotFoundInPATH] m FilePath@@ -71,7 +72,7 @@     if b' then t else f  --- | Check wether a binary is shadowed by another one that comes before+-- | Check whether a binary is shadowed by another one that comes before -- it in PATH. Returns the path to said binary, if any. isShadowed :: FilePath -> IO (Maybe FilePath) isShadowed p = do
lib/GHCup/Prelude/File/Windows.hs view
@@ -1,6 +1,6 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE DataKinds  #-}  {-| Module      : GHCup.Utils.File.Windows@@ -13,19 +13,20 @@ -} module GHCup.Prelude.File.Windows where -import           GHCup.Utils.Dirs-import           GHCup.Prelude.Internal+import GHCup.Prelude.Internal+import GHCup.Query.GHCupDirs+import GHCup.System.Directory  import           Control.Monad.Reader import           Data.List-import qualified GHC.Unicode                  as U+import qualified GHC.Unicode          as U import           System.FilePath-import qualified System.IO.Error              as IOE+import qualified System.IO.Error      as IOE -import qualified System.Win32.Info             as WS-import qualified System.Win32.File             as WS+import qualified System.Win32.File as WS+import qualified System.Win32.Info as WS -import           Data.Bits ((.&.))+import Data.Bits ( (.&.) )  import           Conduit import qualified Data.Conduit.Combinators as C@@ -115,8 +116,8 @@         '\\' : '?'  : '?' : '\\' : _ -> simplifiedPath         '\\' : '\\' : '?' : '\\' : _ -> simplifiedPath         '\\' : '\\' : '.' : '\\' : _ -> simplifiedPath-        '\\' : subpath@('\\' : _) -> "\\\\?\\UNC" <> subpath-        _ -> "\\\\?\\" <> simplifiedPath+        '\\' : subpath@('\\' : _)    -> "\\\\?\\UNC" <> subpath+        _                            -> "\\\\?\\" <> simplifiedPath   where simplifiedPath = simplify path  @@ -128,7 +129,7 @@ simplifyWindows path =   case drive' of     "\\\\?\\" -> drive' <> subpath-    _ -> simplifiedPath+    _         -> simplifiedPath   where     simplifiedPath = joinDrive drive' subpath'     (drive, subpath) = splitDrive path@@ -182,9 +183,9 @@             "." -> go ys' xs             ".." ->               case ys' of-                [] -> go (x : ys') xs+                []       -> go (x : ys') xs                 ".." : _ -> go (x : ys') xs-                _ : ys -> go ys xs+                _ : ys   -> go ys xs             _ -> go (x : ys') xs  rawPrependCurrentDirectory :: FilePath -> IO FilePath
lib/GHCup/Prelude/Internal.hs view
@@ -1,10 +1,10 @@-{-# LANGUAGE CPP                 #-}-{-# LANGUAGE DataKinds           #-}-{-# LANGUAGE FlexibleContexts    #-}-{-# LANGUAGE FlexibleInstances   #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies        #-}-{-# LANGUAGE TypeOperators       #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}  {-| Module      : GHCup.Prelude.Internal@@ -21,37 +21,38 @@ module GHCup.Prelude.Internal where  -import           Control.Applicative-import           Control.Exception.Safe-import           Control.Monad-import           Control.Monad.IO.Class-import           Control.Monad.Reader-import           Data.Bifunctor-import           Data.ByteString                ( ByteString )-import           Data.List                      ( intercalate, stripPrefix, isPrefixOf, dropWhileEnd )-import           Data.Maybe-import           Data.String-import           Data.Text                      ( Text )-import           Data.Versions-import           Data.Word8                  hiding ( isDigit )-import           Data.Variant.Types-import           Data.Variant.Excepts-import           System.IO.Error--import           Control.Retry-import           GHC.IO.Exception+import Control.Applicative+import Control.Exception.Safe+import Control.Monad+import Control.Monad.IO.Class+import Control.Monad.Reader+import Control.Retry+import Data.Bifunctor+import Data.ByteString        ( ByteString )+import Data.Data              ( Proxy )+import Data.List+    ( dropWhileEnd, intercalate, isPrefixOf, stripPrefix )+import Data.Maybe+import Data.String+import Data.Text              ( Text )+import Data.Variant.Excepts+import Data.Variant.Types+import Data.Versions+import Data.Word8             hiding ( isDigit )+import GHC.IO.Exception+import System.IO.Error -import qualified Data.ByteString               as B-import qualified Data.ByteString.Lazy          as L-import qualified Data.Strict.Maybe             as S-import qualified Data.List.Split               as Split-import qualified Data.Text                     as T-import qualified Data.Text.Encoding            as E-import qualified Data.Text.Encoding.Error      as E-import qualified Data.Text.Lazy                as TL-import qualified Data.Text.Lazy.Builder        as B-import qualified Data.Text.Lazy.Builder.Int    as B-import qualified Data.Text.Lazy.Encoding       as TLE+import qualified Data.ByteString            as B+import qualified Data.ByteString.Lazy       as L+import qualified Data.List.Split            as Split+import qualified Data.Strict.Maybe          as S+import qualified Data.Text                  as T+import qualified Data.Text.Encoding         as E+import qualified Data.Text.Encoding.Error   as E+import qualified Data.Text.Lazy             as TL+import qualified Data.Text.Lazy.Builder     as B+import qualified Data.Text.Lazy.Builder.Int as B+import qualified Data.Text.Lazy.Encoding    as TLE   @@ -135,7 +136,14 @@      -> Excepts es m a (!?) em e = lift em >>= (?? e) +(!!?) :: forall e es es' a m+      . (Monad m, e :< es', es' ~ Concat es '[e])+     => Excepts es m (Maybe a)+     -> e+     -> Excepts es' m a+(!!?) em e = appendE @'[e] em >>= (?? e) + lE :: forall e es a m . (Monad m, e :< es) => Either e a -> Excepts es m a lE = liftE . veitherToExcepts . fromEither @@ -220,7 +228,7 @@  hideExcept' :: forall e es es' m              . (Monad m, e :< es, LiftVariant (Remove e es) es')-            => e+            => Proxy e             -> Excepts es m ()             -> Excepts es' m () hideExcept' _ =@@ -258,7 +266,7 @@ throwMaybe :: (Exception a, MonadThrow m) => a -> Maybe b -> m b throwMaybe a m = case m of   Nothing -> throwM a-  Just r -> pure r+  Just r  -> pure r  throwMaybeM :: (Exception a, MonadThrow m) => a -> m (Maybe b) -> m b throwMaybeM a am = do@@ -515,3 +523,4 @@ breakOn needle haystack | needle `isPrefixOf` haystack = ([], haystack) breakOn _ [] = ([], []) breakOn needle (x:xs) = first (x:) $ breakOn needle xs+
+ lib/GHCup/Prelude/JSON.hs view
@@ -0,0 +1,14 @@+module GHCup.Prelude.JSON where++import qualified Data.Text as T++mapHead :: (a -> a) -> [a] -> [a]+mapHead _ []     = []+mapHead f (x:xs) = f x : xs++lower :: Char -> Char+lower = T.head . T.toLower . T.singleton++upper :: Char -> Char+upper = T.head . T.toUpper . T.singleton+
lib/GHCup/Prelude/Logger.hs view
@@ -1,6 +1,6 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE DataKinds        #-}-{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE OverloadedStrings #-}  {-| Module      : GHCup.Utils.Logger@@ -19,25 +19,25 @@   ) where -import           GHCup.Prelude.Logger.Internal-import           GHCup.Types-import           GHCup.Types.Optics-import           GHCup.Utils.Dirs (fromGHCupPath)-import           GHCup.Prelude.Internal-import           GHCup.Prelude.File.Search (findFiles)-import           GHCup.Prelude.File (recycleFile)-import           GHCup.Prelude.String.QQ+import GHCup.Prelude.File            ( recycleFile )+import GHCup.Prelude.File.Search     ( findFiles )+import GHCup.Prelude.Internal+import GHCup.Prelude.Logger.Internal+import GHCup.Prelude.String.QQ+import GHCup.Query.GHCupDirs         ( fromGHCupPath )+import GHCup.Types+import GHCup.Types.Optics -import           Control.Exception.Safe-import           Control.Monad-import           Control.Monad.IO.Class-import           Control.Monad.Reader-import           Prelude                 hiding ( appendFile )-import           System.FilePath-import           System.IO.Error-import           Text.Regex.Posix+import Control.Exception.Safe+import Control.Monad+import Control.Monad.IO.Class+import Control.Monad.Reader+import Prelude                hiding ( appendFile )+import System.FilePath+import System.IO.Error+import Text.Regex.Posix -import qualified Data.ByteString               as B+import qualified Data.ByteString as B   
lib/GHCup/Prelude/Logger/Internal.hs view
@@ -1,6 +1,6 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE DataKinds        #-}-{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE OverloadedStrings #-}  {-| Module      : GHCup.Utils.Logger.Internal@@ -15,18 +15,18 @@ -} module GHCup.Prelude.Logger.Internal where -import           GHCup.Types-import           GHCup.Types.Optics+import GHCup.Types+import GHCup.Types.Optics -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 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 qualified Data.Text                     as T+import qualified Data.Text as T  logInfo :: ( MonadReader env m            , LabelOptic' "loggerConfig" A_Lens env LoggerConfig@@ -50,8 +50,16 @@             )          => Text          -> m ()-logDebug = logInternal Debug+logDebug = logInternal (Debug 1) +logDebug2 :: ( MonadReader env m+            , LabelOptic' "loggerConfig" A_Lens env LoggerConfig+            , MonadIO m+            )+         => Text+         -> m ()+logDebug2 = logInternal (Debug 2)+ logError :: ( MonadReader env m             , LabelOptic' "loggerConfig" A_Lens env LoggerConfig             , MonadIO m@@ -71,12 +79,12 @@   LoggerConfig {..} <- gets @"loggerConfig"   let color' c = if fancyColors then color c else id   let style' = case logLevel of-        Debug   -> style Bold . color' Blue+        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 ]"+        Debug _ -> style' "[ Debug ]"         Info    -> style' "[ Info  ]"         Warn    -> style' "[ Warn  ]"         Error   -> style' "[ Error ]"@@ -89,12 +97,19 @@                 . fmap (\line' -> style' "[ ...   ] " <> line' )                 $ xs -  when (lcPrintDebug || (not lcPrintDebug && (logLevel /= Debug)))-    $ liftIO $ consoleOutter out+  case logLevel of+    Debug lvl+      | Just cfgLvl <- lcPrintDebugLvl+      , lvl <= cfgLvl+      -> liftIO $ consoleOutter out+    Info  -> liftIO $ consoleOutter out+    Warn  -> liftIO $ consoleOutter out+    Error -> liftIO $ consoleOutter out+    _ -> pure ()    -- raw output   let lr = case logLevel of-        Debug   -> "Debug:"+        Debug _ -> "Debug:"         Info    -> "Info:"         Warn    -> "Warn:"         Error   -> "Error:"
lib/GHCup/Prelude/MegaParsec.hs view
@@ -1,5 +1,5 @@-{-# LANGUAGE CPP                  #-}-{-# LANGUAGE OverloadedStrings    #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}  {-| Module      : GHCup.Prelude.MegaParsec@@ -12,24 +12,32 @@ -} module GHCup.Prelude.MegaParsec where -import           GHCup.Types+import GHCup.Types -import           Control.Applicative+import Control.Applicative ( Alternative((<|>), many) )+ #if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )+import Control.Monad.Fail ( MonadFail ) #endif-import           Data.Functor-import           Data.Maybe-import           Data.Text                      ( Text )-import           Data.Versions-import           Data.Void-import           System.FilePath -import qualified Data.List.NonEmpty            as NE-import qualified Data.Text                     as T-import qualified Text.Megaparsec               as MP+import Data.Foldable                  ( asum )+import Data.Functor+import Data.Maybe+import Data.Text                      ( Text )+import Data.Versions+import Data.Void+import System.FilePath+import Text.PrettyPrint.HughesPJClass ( prettyShow ) +import           Data.List.NonEmpty         ( NonEmpty ((:|)) )+import qualified Data.List.NonEmpty         as NE+import qualified Data.Text                  as T+import qualified Text.Megaparsec            as MP+import qualified Text.Megaparsec.Char       as MPC+import qualified Text.Megaparsec.Char.Lexer as L ++ choice' :: (MonadFail f, MP.MonadParsec e s f) => [f a] -> f a choice' []       = fail "Empty list" choice' [x     ] = x@@ -76,13 +84,12 @@   MP.setInput ver   version' - -- | Extracts target triple and version from e.g. --   * armv7-unknown-linux-gnueabihf-8.8.3 --   * armv7-unknown-linux-gnueabihf-8.8.3-ghcTargetVerP :: MP.Parsec Void Text GHCTargetVersion+ghcTargetVerP :: MP.Parsec Void Text TargetVersion ghcTargetVerP =-  (\x y -> GHCTargetVersion x y)+  (\x y -> TargetVersion x y)     <$> (MP.try (Just <$> parseUntil1 (MP.chunk "-" *> verP') <* MP.chunk "-")         <|> ((\ _ x -> x) Nothing <$> mempty)         )@@ -104,7 +111,32 @@       then pure $ prettyVer v       else fail "Oh" +ghcLinkVersion :: MP.Parsec Void Text TargetVersion+ghcLinkVersion =+  (\x y -> TargetVersion x y)+    <$>+       (MP.try (Just <$> parseUntil1 (MP.chunk "-ghc-" *> verP') <* MP.chunk "-")+        <|> ((\ _ x -> x) Nothing <$> mempty)+        )+    <*> (MP.chunk "ghc-" *> version' <* MP.eof)+ where+  verP' :: MP.Parsec Void Text Text+  verP' = do+    v <- version'+    let startsWithDigits =+          and+            . take 3+            . map (\case+                      Numeric  _ -> True+                      Alphanum _ -> False)+            . NE.toList+            . (\(Chunks nec) -> nec)+            $ _vChunks v+    if startsWithDigits && isNothing (_vEpoch v)+      then pure $ prettyVer v+      else fail "Oh" + verP :: MP.Parsec Void Text Text -> MP.Parsec Void Text Versioning verP suffix = do   ver <- parseUntil suffix@@ -140,13 +172,98 @@ -- Obtain the version from the link or shim path -- ../ghc/<ver>/bin/ghc -- ../ghc/<ver>/bin/ghc-<ver>-ghcVersionFromPath :: MP.Parsec Void Text GHCTargetVersion-ghcVersionFromPath =-  do-     beforeBin <- parseUntil1 binDir <* MP.some pathSep-     MP.setInput beforeBin-     _ <- parseTillLastPathSep-     ghcTargetVerP-  where-     binDir = MP.some pathSep <* MP.chunk "bin" *> MP.some pathSep <* MP.takeWhile1P Nothing (not . isPathSeparator) <* MP.eof-     parseTillLastPathSep = (MP.try (parseUntil1 pathSep *> MP.some pathSep) *> parseTillLastPathSep) <|> pure ()+ghcVersionFromPath :: MP.Parsec Void Text TargetVersion+ghcVersionFromPath = toolVersionFromPath ghc++toolVersionFromPath :: Tool -> MP.Parsec Void Text TargetVersion+toolVersionFromPath tool = MP.try legacyParse <|> newParse+ where+  legacyParse = do+    beforeBin <- parseUntil1 binDir <* MP.some pathSep+    MP.setInput beforeBin+    _ <- parseTillLastPathSep+    ghcTargetVerP+   where+    binDir = MP.some pathSep <* MP.chunk "bin" *> MP.some pathSep <* MP.takeWhile1P Nothing (not . isPathSeparator) <* MP.eof+    parseTillLastPathSep = (MP.try (parseUntil1 pathSep *> MP.some pathSep) *> parseTillLastPathSep) <|> pure ()++  newParse = asum $ pathSeparators <&> MP.try . newParse'+  newParse' sep = do+    let toolPath = T.pack $ [sep] <> prettyShow tool <> [sep]+    ver <- parseUntilEmpty toolPath *> MP.chunk toolPath *> parseUntil1 (MP.chunk $ T.singleton sep)+    MP.setInput ver+    ghcTargetVerP+++{--+  -- this doesn'twork because parseUntilEmpty can't take a parser as input+--}++ghcTargetVerRevP :: MP.Parsec Void Text TargetVersionReq+ghcTargetVerRevP = MP.try withRev <|> ((`TargetVersionReq` Nothing) <$> ghcTargetVerP)+ where+  withRev = do+    verText <- parseUntilEmpty "-r"+    rev <- MP.chunk "-r" *> L.decimal+    MP.setInput verText+    tver <- ghcTargetVerP+    pure $ TargetVersionReq tver (Just rev)++verRevP :: MP.Parsec Void Text VersionReq+verRevP = MP.try withRev <|> ((`VersionReq` Nothing) <$> version')+ where+  withRev = do+    verText <- parseUntilEmpty "-r"+    rev <- MP.chunk "-r" *> L.decimal+    MP.setInput verText+    ver <- version'+    pure $ VersionReq ver (Just rev)++-- find a parse in a greedy manner+parseUntilEmpty :: Text -> MP.Parsec Void Text Text+parseUntilEmpty needle = go+ where+  go = do+    prefix <- parseUntil (MP.chunk needle)+    s2 <- MP.try ((<>) <$> MP.chunk needle <*> go) <|> mempty+    pure $ prefix <> s2++versionCmpP :: MP.Parsec Void T.Text VersionCmp+versionCmpP = either (fail . T.unpack) pure =<< (translate <$> (MPC.space *> MP.try (MP.takeWhileP Nothing (`elem` ['>', '<', '=']))) <*> (MPC.space *> versioningEnd))+ where+   translate ">" v  = Right $ VR_gt v+   translate ">=" v = Right $ VR_gteq v+   translate "<" v  = Right $ VR_lt v+   translate "<=" v = Right $ VR_lteq v+   translate "==" v = Right $ VR_eq v+   translate "" v   = Right $ VR_eq v+   translate c  _   = Left $ "unexpected comparator: " <> c++versionRangeP :: MP.Parsec Void T.Text VersionRange+versionRangeP = go <* MP.eof+ where+  go =+    MP.try orParse+      <|> MP.try (fmap SimpleRange andParse)+      <|> fmap (SimpleRange . pure) versionCmpP++  orParse :: MP.Parsec Void T.Text VersionRange+  orParse =+    (\a o -> OrRange a o)+      <$> (MP.try andParse <|> fmap pure versionCmpP)+      <*> (MPC.space *> MP.chunk "||" *> MPC.space *> go)++  andParse :: MP.Parsec Void T.Text (NonEmpty VersionCmp)+  andParse =+    fmap (\h t -> h :| t)+         (MPC.space *> MP.chunk "(" *> MPC.space *> versionCmpP)+      <*> MP.try (MP.many (MPC.space *> MP.chunk "&&" *> MPC.space *> versionCmpP))+      <*  MPC.space+      <*  MP.chunk ")"+      <*  MPC.space++versioningEnd :: MP.Parsec Void T.Text Versioning+versioningEnd =+  MP.try (verP (MP.chunk " " <|> MP.chunk ")" <|> MP.chunk "&&") <* MPC.space)+    <|> versioning'+
lib/GHCup/Prelude/Posix.hs view
@@ -4,7 +4,7 @@ -- | Enables ANSI support on windows, does nothing on unix. -- -- Returns 'Left str' on errors and 'Right bool' on success, where--- 'bool' markes whether ansi support was already enabled.+-- 'bool' marks whether ansi support was already enabled. -- -- This function never crashes. --
lib/GHCup/Prelude/Process/Posix.hs view
@@ -1,9 +1,9 @@+{-# LANGUAGE CApiFFI #-} {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MultiWayIf #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE DataKinds  #-}-{-# LANGUAGE MultiWayIf  #-}-{-# LANGUAGE CApiFFI #-}  {-| Module      : GHCup.Utils.File.Posix@@ -16,47 +16,44 @@ -} module GHCup.Prelude.Process.Posix where -import           GHCup.Utils.Dirs-import           GHCup.Prelude.File-import           GHCup.Prelude.File.Posix-import           GHCup.Prelude-import           GHCup.Prelude.Logger-import           GHCup.Types-import           GHCup.Types.Optics+import GHCup.Prelude+import GHCup.Prelude.File.Posix+import GHCup.Query.GHCupDirs+import GHCup.Types+import GHCup.Types.Optics  import           Control.Concurrent import           Control.Concurrent.Async-import qualified Control.Exception              as E+import qualified Control.Exception                as E import           Control.Exception.Safe import           Control.Monad import           Control.Monad.Reader import           Control.Monad.Trans.State.Strict-import           Data.ByteString                ( ByteString )+import           Data.ByteString                  ( ByteString ) import           Data.Foldable import           Data.IORef-import           Data.Sequence                  ( Seq, (|>) ) import           Data.List+import           Data.Sequence                    ( Seq, (|>) ) import           Data.Word8 import           GHC.IO.Exception-import           System.IO                      ( stderr )-import           System.IO.Error      hiding    ( catchIOError ) import           System.FilePath+import           System.IO                        ( stderr )+import           System.IO.Error                  hiding ( catchIOError ) import           System.Posix.Directory import           System.Posix.IO-import           System.Posix.Process           ( ProcessStatus(..) )+import           System.Posix.Process             ( ProcessStatus (..) ) import           System.Posix.Types  -import qualified Control.Exception             as EX-import qualified Data.Sequence                 as Sq-import qualified Data.Text                     as T-import qualified Data.Text.Encoding            as E-import qualified System.Posix.Process          as SPP-import qualified System.Console.Terminal.Size  as TP-import qualified Data.ByteString               as BS-import qualified Data.ByteString.Lazy          as BL-import qualified System.Posix.IO.ByteString.Ext-                                               as SPIB+import qualified Control.Exception              as EX+import qualified Data.ByteString                as BS+import qualified Data.ByteString.Lazy           as BL+import qualified Data.Sequence                  as Sq+import qualified Data.Text                      as T+import qualified Data.Text.Encoding             as E+import qualified System.Console.Terminal.Size   as TP+import qualified System.Posix.IO.ByteString.Ext as SPIB+import qualified System.Posix.Process           as SPP   @@ -117,9 +114,10 @@         $ forkIO         $ EX.handle (\(_ :: IOException) -> pure ())         $ EX.finally-            (if verbose-              then tee fd stdoutRead-              else printToRegion fd stdoutRead 6 pState no_color+            (case verbose of+              Verbosity i+                | i > 0 -> tee fd stdoutRead+                | otherwise -> printToRegion fd stdoutRead 6 pState no_color             )             (putMVar done ()) @@ -373,7 +371,7 @@                -> Either ProcessError () toProcessError exe args mps = case mps of   Just (SPP.Exited (ExitFailure xi)) -> Left $ NonZeroExit xi exe args-  Just (SPP.Exited ExitSuccess    ) -> Right ()+  Just (SPP.Exited ExitSuccess    )  -> Right ()   Just (Terminated _ _             ) -> Left $ PTerminated exe args   Just (Stopped _                  ) -> Left $ PStopped exe args   Nothing                            -> Left $ NoSuchPid exe args
lib/GHCup/Prelude/Process/Windows.hs view
@@ -1,6 +1,6 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE DataKinds  #-}  {-| Module      : GHCup.Utils.Process.Windows@@ -13,32 +13,33 @@ -} module GHCup.Prelude.Process.Windows where -import           GHCup.Utils.Dirs-import           GHCup.Prelude.File.Search-import           GHCup.Prelude.Logger.Internal-import           GHCup.Types-import           GHCup.Types.Optics+import GHCup.Prelude.File.Search+import GHCup.Prelude.Logger.Internal+import GHCup.Query.GHCupDirs+import GHCup.System.Directory+import GHCup.Types+import GHCup.Types.Optics -import           Control.Concurrent-import           Control.DeepSeq-import           Control.Exception.Safe-import           Control.Monad-import           Control.Monad.Reader-import           Data.List-import           Foreign.C.Error-import           GHC.IO.Exception-import           GHC.IO.Handle-import           System.Environment-import           System.FilePath-import           System.IO-import           System.Process-import           System.Win32.Info (getSystemDirectory, getWindowsDirectory)+import Control.Concurrent+import Control.DeepSeq+import Control.Exception.Safe+import Control.Monad+import Control.Monad.Reader+import Data.List+import Foreign.C.Error+import GHC.IO.Exception+import GHC.IO.Handle+import System.Environment+import System.FilePath+import System.IO+import System.Process+import System.Win32.Info      ( getSystemDirectory, getWindowsDirectory ) -import qualified Control.Exception             as EX-import qualified Data.ByteString               as BS-import qualified Data.ByteString.Lazy          as BL-import qualified Data.Map.Strict               as Map-import qualified Data.Text                     as T+import qualified Control.Exception    as EX+import qualified Data.ByteString      as BS+import qualified Data.ByteString.Lazy as BL+import qualified Data.Map.Strict      as Map+import qualified Data.Text            as T   @@ -49,7 +50,7 @@                -> Either ProcessError () toProcessError exe args exitcode = case exitcode of   (ExitFailure xi) -> Left $ NonZeroExit xi exe args-  ExitSuccess -> Right ()+  ExitSuccess      -> Right ()   -- | @readCreateProcessWithExitCode@ works exactly like 'readProcessWithExitCode' except that it
lib/GHCup/Prelude/String/QQ.hs view
@@ -1,52 +1,23 @@ {-# LANGUAGE TemplateHaskellQuotes #-} -{-|-Module      : GHCup.Utils.String.QQ-Description : String quasi quoters-Copyright   : (c) Audrey Tang <audreyt@audreyt.org> 2019, Julian Ospald <hasufell@posteo.de> 2020-License     : LGPL-3.0-Maintainer  : hasufell@hasufell.de-Stability   : experimental-Portability : portable--QuasiQuoter for non-interpolated strings, texts and bytestrings.--The "s" quoter contains a multi-line string with no interpolation at all,-except that the leading newline is trimmed and carriage returns stripped.--@-{-\# LANGUAGE QuasiQuotes #-}-import Data.Text (Text)-import Data.String.QQ-foo :: Text -- "String", "ByteString" etc also works-foo = [s|-Well here is a-    multi-line string!-|]-@--Any instance of the IsString type is permitted.--(For GHC versions 6, write "[$s||]" instead of "[s||]".)---}+{-# LANGUAGE QuasiQuotes #-} module GHCup.Prelude.String.QQ   ( s   ) where  -import           Data.Char-import           GHC.Exts                       ( IsString(..) )-import           Language.Haskell.TH.Quote+import Data.Char+import GHC.Exts                  ( IsString (..) )+import Language.Haskell.TH.Quote  -- | QuasiQuoter for a non-interpolating ASCII IsString literal. -- The pattern portion is undefined. s :: QuasiQuoter s = QuasiQuoter-  (\s' -> case all isAscii s' of-    True  -> (\a -> [|fromString a|]) . trimLeadingNewline . removeCRs $ s'-    False -> fail "Not ascii"+  (\s' -> if all isAscii s'+    then (\a -> [|fromString a|]) . trimLeadingNewline . removeCRs $ s'+    else fail "Not ascii"   )   (error "Cannot use s as a pattern")   (error "Cannot use s as a type")
+ lib/GHCup/Prelude/Version.hs view
@@ -0,0 +1,110 @@+{-|+Module      : GHCup.Prelude.Version+Description : Manipulating versions+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Prelude.Version where++import GHCup.Types++import Control.Exception.Safe ( MonadThrow )+import Control.Monad.Catch    ( throwM )+import Data.List.NonEmpty     ( NonEmpty ((:|)) )+import Data.Text              ( Text )+import Data.Void              ( Void )+import GHCup.Errors           ( ParseError (..) )+import Text.Megaparsec++import qualified Data.List.NonEmpty as NE+import qualified Data.Text          as T+import qualified Data.Versions      as V+import Control.Exception (Exception(displayException))+++versionCmp :: V.Versioning -> VersionCmp -> Bool+versionCmp ver1 (VR_gt ver2)   = ver1 > ver2+versionCmp ver1 (VR_gteq ver2) = ver1 >= ver2+versionCmp ver1 (VR_lt ver2)   = ver1 < ver2+versionCmp ver1 (VR_lteq ver2) = ver1 <= ver2+versionCmp ver1 (VR_eq ver2)   = ver1 == ver2++versionRange :: V.Versioning -> VersionRange -> Bool+versionRange ver' (SimpleRange cmps) = all (versionCmp ver') cmps+versionRange ver' (OrRange cmps range) =+  versionRange ver' (SimpleRange cmps) || versionRange ver' range++pvpToVersion :: MonadThrow m => V.PVP -> Text -> m V.Version+pvpToVersion pvp_ rest =+  either (\_ -> throwM $ ParseError "Couldn't convert PVP to Version") pure . V.version . (<> rest) . V.prettyPVP $ pvp_++-- | Convert a version to a PVP and unparsable rest.+--+-- -- prop> \v -> let (Just (pvp', r)) = versionToPVP v in pvpToVersion pvp' r === Just v+versionToPVP :: MonadThrow m => V.Version -> m (V.PVP, Text)+versionToPVP (V.Version (Just _) _ _ _) = throwM $ ParseError "Unexpected epoch"+versionToPVP v = case parse pvp'' "Version->PVP" $ V.prettyVer v of+  Left _  -> throwM $ ParseError "Couldn't convert Version to PVP"+  Right r -> pure r+ where+   pvp'' :: Parsec Void T.Text (V.PVP, T.Text)+   pvp'' = do+     p <- V.pvp'+     s <- getParserState+     pure (p, stateInput s)++pvpFromList :: [Int] -> V.PVP+pvpFromList = V.PVP . NE.fromList . fmap fromIntegral++-- | Extract (major, minor) from any version.+getMajorMinorV :: MonadThrow m => V.Version -> m (Int, Int)+getMajorMinorV (V.Version _ (V.Chunks (V.Numeric x :| V.Numeric y : _)) _ _) = pure (fromIntegral x, fromIntegral y)+getMajorMinorV _ = throwM $ ParseError "Could not parse X.Y from version"++matchMajor :: V.Version -> Int -> Int -> Bool+matchMajor v' major' minor' = case getMajorMinorV v' of+  Just (x, y) -> x == major' && y == minor'+  Nothing     -> False++-- | Match PVP prefix.+--+-- >>> matchPVPrefix [pver|8.8|] [pver|8.8.4|]+-- True+-- >>> matchPVPrefix [pver|8|] [pver|8.8.4|]+-- True+-- >>> matchPVPrefix [pver|8.10|] [pver|8.8.4|]+-- False+-- >>> matchPVPrefix [pver|8.10|] [pver|8.10.7|]+-- True+matchPVPrefix :: V.PVP -> V.PVP -> Bool+matchPVPrefix (toL -> prefix) (toL -> full) = and $ zipWith (==) prefix full++toL :: V.PVP -> [Int]+toL (V.PVP inner) = fmap fromIntegral $ NE.toList inner++-- | Expand a list of version patterns describing a string such as "%v-%h".+--+-- >>> expandVersionPattern (either (const Nothing) Just $ version "3.4.3") "a386748" "a3867484ccc391daad1a42002c3a2ba6a93c5221" "v0.1.20.0-119-ga386748" "issue-998" [CabalVer, S "-", GitHashShort, S "-", GitHashLong, S "-", GitBranchName, S "-", GitDescribe, S "-coco"]+-- Version {_vEpoch = Nothing, _vChunks = Chunks (Numeric 3 :| [Numeric 4,Numeric 3]), _vRel = Just (Release (Alphanum "a386748-a3867484ccc391daad1a42002c3a2ba6a93c5221-issue-998-v0" :| [Numeric 1,Numeric 20,Alphanum "0-119-ga386748-coco"])), _vMeta = Nothing}+expandVersionPattern :: MonadFail m+                     => Maybe V.Version  -- ^ cabal ver+                     -> String         -- ^ git hash (short), if any+                     -> String         -- ^ git hash (long), if any+                     -> String         -- ^ git describe output, if any+                     -> String         -- ^ git branch name, if any+                     -> [VersionPattern]+                     -> m V.Version+expandVersionPattern cabalVer gitHashS gitHashL gitDescribe gitBranch+  = either (fail . displayException) pure . V.version . T.pack . go+ where+  go []                 = ""+  go (CabalVer:xs)      = T.unpack (maybe T.empty V.prettyVer cabalVer) <> go xs+  go (GitHashShort:xs)  = gitHashS <> go xs+  go (GitHashLong:xs)   = gitHashL <> go xs+  go (GitDescribe:xs)   = gitDescribe <> go xs+  go (GitBranchName:xs) = gitBranch <> go xs+  go (S str:xs)         = str <> go xs+
lib/GHCup/Prelude/Version/QQ.hs view
@@ -1,8 +1,8 @@ {-# OPTIONS_GHC -Wno-orphans    #-}-{-# LANGUAGE CPP                #-}+{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveLift         #-}-{-# LANGUAGE FlexibleInstances  #-}+{-# LANGUAGE DeriveLift #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TemplateHaskellQuotes #-} @@ -18,17 +18,17 @@ -} module GHCup.Prelude.Version.QQ where -import           Data.Data-import           Data.Text                      ( Text )-import           Data.Versions+import Data.Data+import Data.Text     ( Text )+import Data.Versions #if !MIN_VERSION_base(4,13,0)-import           GHC.Base+import GHC.Base #endif+import qualified Data.Text                  as T import           Language.Haskell.TH-import           Language.Haskell.TH.Quote      ( QuasiQuoter(..) )-import           Language.Haskell.TH.Syntax     ( dataToExpQ )-import qualified Data.Text                     as T-import qualified Language.Haskell.TH.Syntax    as TH+import           Language.Haskell.TH.Quote  ( QuasiQuoter (..) )+import           Language.Haskell.TH.Syntax ( dataToExpQ )+import qualified Language.Haskell.TH.Syntax as TH   #if !MIN_VERSION_base(4,13,0)
lib/GHCup/Prelude/Windows.hs view
@@ -1,21 +1,21 @@-{-# LANGUAGE CPP                   #-}-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}  module GHCup.Prelude.Windows where  -import           Control.Exception.Safe-import           Control.Monad+import Control.Exception.Safe+import Control.Monad #if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )+import Control.Monad.Fail ( MonadFail ) #endif-import           Data.Bits+import Data.Bits -import           System.Win32.Console-import           System.Win32.File     hiding ( copyFile )-import           System.Win32.Types+import System.Win32.Console+import System.Win32.File    hiding ( copyFile )+import System.Win32.Types   @@ -23,7 +23,7 @@ -- | Enables ANSI support on windows, does nothing on unix. -- -- Returns 'Left str' on errors and 'Right bool' on success, where--- 'bool' markes whether ansi support was already enabled.+-- 'bool' marks whether ansi support was already enabled. -- -- This function never crashes. --
− lib/GHCup/Prompts.hs
@@ -1,32 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE FlexibleContexts #-}--module GHCup.Prompts-  ( PromptQuestion,-    PromptResponse (..),-    getUserPromptResponse,-  )-where--import Control.Monad.Reader-import qualified Data.Text as T-import qualified Data.Text.IO as TIO-import GHCup.Prelude.Logger-import GHCup.Types.Optics-import GHCup.Types (PromptQuestion, PromptResponse(..))--getUserPromptResponse :: ( HasLog env-                         , MonadReader env m-                         , MonadIO m)-                      => PromptQuestion-                      -> PromptResponse -- ^ Default reponse to use if user doesn't type explicit response (e.g. just presses Return)-                      -> m PromptResponse-getUserPromptResponse prompt defaultResponse = do-  logInfo prompt-  resp <- liftIO TIO.getLine-  pure $-    if T.null resp-      then defaultResponse-      else if resp `elem` ["YES", "yes", "y", "Y"]-        then PromptYes-        else PromptNo
+ lib/GHCup/Query.hs view
@@ -0,0 +1,14 @@+module GHCup.Query+  (module GHCup.Query.DB+  ,module GHCup.Query.GHCupDirs+  ,module GHCup.Query.Metadata+  ,module GHCup.Query.Symlink+  ,module GHCup.Query.System+  )+  where++import GHCup.Query.DB+import GHCup.Query.GHCupDirs+import GHCup.Query.Metadata+import GHCup.Query.Symlink+import GHCup.Query.System
+ lib/GHCup/Query/DB.hs view
@@ -0,0 +1,398 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PatternSynonyms #-}++module GHCup.Query.DB where++import GHCup.Errors+import GHCup.Hardcoded.Version+import GHCup.Input.SymlinkSpec+import GHCup.Legacy.Utils+import GHCup.Prelude+import GHCup.Prelude.MegaParsec+import GHCup.Query.GHCupDirs+import GHCup.Types+import GHCup.Types.Optics++import Control.DeepSeq                ( force )+import Control.Exception+    ( Exception (displayException), SomeException, evaluate )+import Control.Exception.Safe         ( try )+import Control.Monad                  ( forM )+import Control.Monad.Catch            ( MonadCatch )+import Control.Monad.IO.Class         ( MonadIO, liftIO )+import Control.Monad.Reader           ( MonadReader )+import Control.Monad.Trans            ( lift )+import Data.Either                    ( rights )+import Data.Functor                   ( (<&>) )+import Data.List                      ( nub, nubBy )+import Data.Set                       ( Set )+import Data.Text                      ( Text )+import Data.Variant.Excepts+    ( Excepts, liftE, pattern V, pattern VLeft, pattern VRight, runE, throwE )+import Data.Versions                  ( Version, version )+import Data.Yaml                      ( decodeEither' )+import Optics                         ( preview, (%) )+import System.FilePath                ( takeExtension, (</>) )+import System.IO.Error                ( doesNotExistErrorType )+import Text.PrettyPrint.HughesPJClass ( prettyShow )++import qualified Data.ByteString as B+import qualified Data.Map.Strict as Map+import qualified Data.Set        as Set+import qualified Data.Text       as T+import qualified Data.Text.IO    as T+import qualified Text.Megaparsec as MP++++    --------------------+    --[ DownloadInfo ]--+    --------------------+++getInstallMetadata ::+  ( MonadIO m+  , MonadCatch m+  , MonadReader env m+  , HasDirs env+  , HasLog env+  , MonadFail m+  )+  => Tool+  -> TargetVersion+  -> Excepts '[FileDoesNotExistError, ParseError] m InstallMetadata+getInstallMetadata tool tver = do+  f <- lift $ recordedInstallationSpecFile tool tver+  -- we have to trigger 'doesNotExistErrorType' explicitly, since libyaml swallows it, so+  -- we have to avoid 'decodeFileEither':+  --   https://github.com/snoyberg/yaml/blob/7380d7f560daa2f45ff265d425866f497ca07966/libyaml/src/Text/Libyaml.hs#L656-L657+  r <- liftIOException doesNotExistErrorType (FileDoesNotExistError f) $ liftIO $ do+    contents <- B.readFile f+    pure $ decodeEither' contents+  either (throwE . ParseError . displayException) pure r+++getInstalledRevision ::+  ( MonadIO m+  , MonadCatch m+  , MonadReader env m+  , HasDirs env+  , HasLog env+  , MonadFail m+  )+  => Tool+  -> TargetVersion+  -> m Int+getInstalledRevision tool tver = do+  runE (getInstallMetadata tool tver) >>= \case+    VLeft _ -> pure 0+    VRight InstallMetadata{..} -> pure _imRevision+++    --------------------+    --[ Symlink spec ]--+    --------------------+++getSymlinkSpec ::+  ( MonadReader env m+  , HasDirs env+  , HasPlatformReq env+  , HasLog env+  , MonadIOish m+  )+  => Tool+  -> TargetVersion+  -> Excepts '[FileDoesNotExistError, ParseError, NoInstallInfo] m [SymlinkFileSpec]+getSymlinkSpec tool tver = do+  spec <- getSymlinkSpec' tool tver++  -- substitute+  pure $ spec <&> substituteSpec++getSymlinkSpec' ::+  ( MonadReader env m+  , HasDirs env+  , HasPlatformReq env+  , HasLog env+  , MonadIOish m+  )+  => Tool+  -> TargetVersion+  -> Excepts+       '[FileDoesNotExistError, ParseError, NoInstallInfo]+       m+       [SymlinkSpec [Either Char Version]]+getSymlinkSpec' tool tver = do+  dli <- liftE $ getInstallMetadata tool tver+  logDebug2 $ T.pack $ show dli+  spec <- preview (imResolvedInstallSpec % isExeSymLinked) dli ?? NoInstallInfo tool tver++  forM spec (liftE . parseSymlinkSpec (_tvVersion tver))++getSymlinkSpecPortable ::+  ( MonadReader env m+  , HasDirs env+  , HasPlatformReq env+  , HasLog env+  , MonadIOish m+  )+  => Tool+  -> TargetVersion+  -> m [SymlinkFileSpec]+getSymlinkSpecPortable tool tver = do+  runE (getSymlinkSpec tool tver) >>= \case+    VRight r -> pure r+    VLeft (V pe@(ParseError _)) -> fail $ prettyHFError pe+    VLeft _ -> do -- legacy+      if | tool == ghc   -> do+             pfreq <- getPlatformReq+             pure $ defaultGHCExeSymLinked pfreq tver (ghcBinaries pfreq tver)+         | tool == cabal -> pure []+         | tool == stack -> pure []+         | tool == hls   -> pure []+         | tool == ghcup -> pure [] -- Hm+         | otherwise     -> pure []+++++    -----------------+    --[ Installed ]--+    -----------------+++-- | Returns 'Nothing' for legacy installs.+getInstalledFiles :: ( MonadIO m+                     , MonadCatch m+                     , MonadReader env m+                     , HasDirs env+                     , MonadFail m+                     )+                  => Tool+                  -> TargetVersion+                  -> m (Maybe [FilePath])+getInstalledFiles t v' = hideErrorDef [doesNotExistErrorType] Nothing $ do+  f <- recordedInstallationFile t v'+  (force -> !c) <- liftIO+    (readFile f >>= evaluate)+  pure (Just $ lines c)+++isInstalled ::+  ( MonadReader env m+  , HasDirs env+  , HasLog env+  , MonadIOish m+  )+  => Tool+  -> TargetVersion+  -> m (Maybe Int)+isInstalled tool ver+  | tool == ghc =+      isInstalledNew $ ghcInstalled ver+  | tool == hls =+      isInstalledNew $ hlsInstalled (_tvVersion ver)+  | tool == cabal =+      isInstalledNew $ cabalInstalled (_tvVersion ver)+  | tool == stack =+      isInstalledNew $ stackInstalled (_tvVersion ver)+  | tool == ghcup =+      if ghcUpVer' == ver+      then pure $ Just 0+      else pure Nothing+  | otherwise = isInstalledNew (pure False)+ where+   -- for new installations we can just check the DB+  isInstalledNew fallback = do+    runE (getInstallMetadata tool ver) >>= \case+      VLeft _ -> do+        b <- fallback+        if b+        then pure (Just 0)+        else pure Nothing+      VRight InstallMetadata{..} -> pure (Just _imRevision)++getInstalledVersions ::+  ( MonadReader env m+  , HasDirs env+  , HasLog env+  , MonadIOish m+  )+  => Tool+  -> Maybe T.Text+  -> m [VersionRev]+getInstalledVersions tool mtarget = do+  r <- getInstalledVersions' tool+  pure $ extract' r+ where+  extract' = fmap (\TargetVersionRev{..} -> VersionRev (_tvVersion _tvrTargetVer) _tvrRev)+           . filter (\TargetVersionRev{..} -> _tvTarget _tvrTargetVer == mtarget)++getInstalledVersions' ::+  ( MonadReader env m+  , HasDirs env+  , HasLog env+  , MonadIOish m+  )+  => Tool+  -> m [TargetVersionRev]+getInstalledVersions' tool+  | tool == ghc = do+      new <- getInstalledNew+      legacy <- fmap rights getInstalledGHCs+      pure $ nubBy (\a b -> _tvrTargetVer a == _tvrTargetVer b) (new ++ (unsafeToTargetVersionRev <$> legacy))+  | tool == cabal = do+      new <- getInstalledNew+      legacy <- fmap (fmap mkTVer . rights) getInstalledCabals+      pure $ nubBy (\a b -> _tvrTargetVer a == _tvrTargetVer b) (new ++ (unsafeToTargetVersionRev <$> legacy))+  | tool == stack = do+      new <- getInstalledNew+      legacy <- fmap (fmap mkTVer . rights)  getInstalledStacks+      pure $ nubBy (\a b -> _tvrTargetVer a == _tvrTargetVer b) (new ++ (unsafeToTargetVersionRev <$> legacy))+  | tool == hls = do+      new <- getInstalledNew+      legacy <- fmap (fmap mkTVer . rights) getInstalledHLSs+      pure $ nubBy (\a b -> _tvrTargetVer a == _tvrTargetVer b) (new ++ (unsafeToTargetVersionRev <$> legacy))+  | tool == ghcup = do+      pure [unsafeToTargetVersionRev ghcUpVer']+  | otherwise = getInstalledNew+ where+  parseGHCVer = throwEither . MP.parse ghcTargetVerP "getInstalledVersions'" . T.pack+  getInstalledNew = do+    Dirs {..}  <- getDirs+    let dbPath = fromGHCupPath dbDir </> prettyShow tool+    -- we have to ignore '.spec' and the 'set' file+    contents <- fmap (filter (\f -> takeExtension f `notElem` [".spec", ".set"] && f /= "set"))+      $ liftIO $ handleIO' doesNotExistErrorType (\_ -> pure []) $ listDirectoryFiles dbPath+    forM contents $ \c -> do+      tv <- parseGHCVer c+      rev <- getInstalledRevision tool tv+      pure $ TargetVersionRev tv rev+++getAllInstalledTools ::+  ( MonadReader env m+  , HasGHCupInfo env+  , HasDirs env+  , HasPlatformReq env+  , HasLog env+  , MonadIOish m+  )+  => Maybe [Tool]+  -> Excepts '[ParseError] m (Map.Map Tool (Map.Map (Maybe Text) ([VersionRev], Maybe VersionRev)))+getAllInstalledTools mtools = do+  Dirs{..} <- lift getDirs+  tools <- case mtools of+    Nothing -> do+      newTools <- fmap Tool <$> liftIO (listDirectoryDirs $ fromGHCupPath dbDir)+      pure (nub $ ghcup:ghc:cabal:hls:stack:newTools)+    Just tools'+      -- for GHC we also need to fetch HLS info, so we can display 'hls-powered'+      | ghc `elem` tools' -> pure (nub $ hls:tools')+      | otherwise -> pure (nub tools')+  fmap Map.fromList $ forM tools $ \newTool -> do+    vs <- lift $ getInstalledVersions' newTool+    -- add information on which is the 'set' version, if any+    nm <- Map.traverseWithKey (trav newTool) (groupByTarget' vs)++    pure (newTool, nm)+ where+  trav tool mtarget vers' = do+    mv <- getSetVersion tool mtarget+    pure (vers', mv)++++    -----------+    --[ Set ]--+    -----------+++getSetVersion' ::+  ( MonadReader env m+  , HasDirs env+  , HasLog env+  , MonadIOish m+  )+  => Tool+  -> Maybe T.Text+  -> Excepts '[ParseError] m (Maybe (VersionRev, Maybe FilePath))+getSetVersion' tool target = do+  setFile <- lift $ recordedSetVersionFile tool target+  ec <- liftIO $ try @_ @SomeException (T.readFile setFile)+  case ec of+    Left _+      | tool == ghc ->+          lift $ fmap ((,Nothing) . (`VersionRev` 0) . _tvVersion) <$> ghcSet target+      | tool == cabal ->+          lift $ fmap ((,Nothing) . (`VersionRev` 0)) <$> cabalSet+      | tool == hls ->+          lift $ fmap ((,Nothing) . (`VersionRev` 0)) <$> hlsSet+      | tool == stack ->+          lift $ fmap ((,Nothing) . (`VersionRev` 0)) <$> stackSet+      | tool == ghcup ->+          pure (Just ((`VersionRev` 0) $ _tvVersion ghcUpVer', Nothing))+      | otherwise -> pure Nothing+    Right c -> do+      ver <- either (throwE . ParseError . displayException) pure . version $ c+      rev <- getInstalledRevision tool (TargetVersion target ver)+      pure $ Just (VersionRev ver rev, Just setFile)++getSetVersion ::+  ( MonadReader env m+  , HasDirs env+  , HasLog env+  , MonadIOish m+  )+  => Tool+  -> Maybe T.Text+  -> Excepts '[ParseError] m (Maybe VersionRev)+getSetVersion tool = (fmap . fmap) fst . getSetVersion' tool++isSet ::+  ( MonadReader env m+  , HasDirs env+  , HasLog env+  , MonadIOish m+  )+  => Tool+  -> TargetVersion+  -> Excepts '[ParseError] m (Maybe Int)+isSet tool tver = do+  mv <- (fmap . fmap) fst . getSetVersion' tool $ _tvTarget tver+  case mv of+    Just v ->+      if _tvVersion tver == _vrVersion v+      then pure $ Just (_vrRev v)+      else pure Nothing+    _ -> pure Nothing+++++    -------------+    --[ Other ]--+    -------------+++groupByTarget :: [(TargetVersionRev, VersionMetadata)] -> Map.Map (Maybe Text) [(VersionRev, VersionMetadata)]+groupByTarget = foldr (\(TargetVersionRev{..}, vm) -> Map.alter (f (VersionRev (_tvVersion _tvrTargetVer) _tvrRev) vm) (_tvTarget _tvrTargetVer)) mempty+ where+  f tvVersion' vm Nothing   = Just [(tvVersion', vm)]+  f tvVersion' vm (Just xs) = Just ((tvVersion', vm):xs)++groupByTarget' :: [TargetVersionRev] -> Map.Map (Maybe Text) [VersionRev]+groupByTarget' = foldr (\(TargetVersionRev{..}) -> Map.alter (f (VersionRev (_tvVersion _tvrTargetVer) _tvrRev)) (_tvTarget _tvrTargetVer)) mempty+ where+  f tvVersion' Nothing   = Just [tvVersion']+  f tvVersion' (Just xs) = Just (tvVersion':xs)++groupByTargetS :: [(TargetVersion, VersionMetadata)] -> Map.Map (Maybe Text) (Set (Version, VersionMetadata))+groupByTargetS = foldr (\(TargetVersion{..}, vm) -> Map.alter (f _tvVersion vm) _tvTarget) mempty+ where+  f tvVersion' vm Nothing   = Just $ Set.singleton (tvVersion', vm)+  f tvVersion' vm (Just xs) = Just $ Set.insert (tvVersion', vm) xs+
+ lib/GHCup/Query/DB/HLS.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PatternSynonyms #-}++module GHCup.Query.DB.HLS where++import GHCup.Legacy.Utils+import GHCup.Prelude+import GHCup.Query.DB+import GHCup.Types+import GHCup.Types.Optics++import Control.Monad.Reader ( MonadReader )+import Data.List            ( stripPrefix )+import Data.Maybe           ( catMaybes )+import Data.Variant.Excepts ( pattern VLeft, pattern VRight, runE )+import Data.Versions        ( Version, version )+import Safe                 ( headMay )++import qualified Data.Text as T+++getHLSGHCs ::+  ( MonadReader env m+  , HasDirs env+  , HasPlatformReq env+  , HasLog env+  , MonadIOish m+  )+  => Version+  -> m [Version]+getHLSGHCs hlsVer = do+  vspec <- runE $ getSymlinkSpec hls (mkTVer hlsVer)+  case vspec of+    VRight (fmap (\SymlinkSpec{..} -> _slLinkName) -> bins) -> do+      let extractGHCVerFromBinary bin = do+            prefix <- headMay $ splitOn "~" bin+            s <- stripPrefix "haskell-language-server-" prefix+            either (const Nothing) pure . version . T.pack $ s+          ghcs = catMaybes $ extractGHCVerFromBinary <$> bins+      pure ghcs+    -- legacy+    VLeft _ -> do+      hlsGHCVersions' hlsVer+
+ lib/GHCup/Query/GHCupDirs.hs view
@@ -0,0 +1,569 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE ViewPatterns #-}++{-|+Module      : GHCup.Query.GHCupDirs+Description : Definition of GHCup directories+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Query.GHCupDirs+  ( getAllDirs+  , ghcupBaseDir+  , ghcupConfigFile+  , ghcupCacheDir+  , ghcupGHCBaseDir+  , toolInstallDestination+  , toolBaseDir+  , ghcupGHCDir+  , ghcupHLSBaseDir+  , ghcupHLSDir+  , mkGhcupTmpDir+  , parseGHCupGHCDir+  , parseGHCupHLSDir+  , relativeSymlink+  , withGHCupTmpDir+  , getConfigFilePath+  , getConfigFilePath'+  , useXDG+  , cleanupTrash+  , ghcupMsys2BinDirs+  , ghcupMsys2BinDirs'++  , GHCupPath+  , appendGHCupPath+  , fromGHCupPath+  , createTempGHCupDirectory+  , getGHCupTmpDirs++  , removeDirectory+  , removeDirectoryRecursive+  , removePathForcibly++  , listDirectoryFiles+  , listDirectoryDirs+  )+where+++import GHCup.Errors+import GHCup.Prelude.File.Search+import GHCup.Prelude.Logger.Internal ( logDebug, logWarn )+import GHCup.Prelude.MegaParsec+import GHCup.Prelude.String.QQ+import GHCup.System.Directory+import GHCup.Types+import GHCup.Types.JSON+    ()+import GHCup.Types.Optics+#if defined(IS_WINDOWS)+import GHCup.Prelude.Windows ( isWindows )+#else+import GHCup.Prelude.Posix ( isWindows )+#endif++import Control.DeepSeq                ( NFData, rnf )+import Control.Exception.Safe+import Control.Monad+import Control.Monad.IO.Unlift+import Control.Monad.Reader+import Control.Monad.Trans.Resource   hiding ( throwM )+import Data.Bifunctor+import Data.ByteString                ( ByteString )+import Data.List+import Data.Maybe+import Data.Variant.Excepts+import Data.Versions+import GHC.IO.Exception               ( IOErrorType (NoSuchThing) )+import Optics                         hiding ( uncons )+import Safe+import System.Environment+import System.FilePath+import System.Info+import System.IO.Error                ( ioeGetErrorType )+import System.IO.Temp+import Text.PrettyPrint.HughesPJClass ( prettyShow )+import Text.Regex.Posix++import qualified Data.ByteString  as BS+import qualified Data.Text        as T+import qualified Data.Yaml.Aeson  as Y+import qualified System.Directory as SD+import qualified Text.Megaparsec  as MP++++    ---------------------------+    --[ GHCupPath utilities ]--+    ---------------------------++-- | A 'GHCupPath' is a safe sub-path that can be recursively deleted.+--+-- The constructor is not exported.+newtype GHCupPath+  = GHCupPath FilePath+  deriving (Eq, Ord, Show)++instance NFData GHCupPath where+  rnf (GHCupPath fp) = rnf fp++appendGHCupPath :: GHCupPath -> FilePath -> GHCupPath+appendGHCupPath (GHCupPath gp) fp = GHCupPath (gp </> fp)++fromGHCupPath :: GHCupPath -> FilePath+fromGHCupPath (GHCupPath gp) = gp++createTempGHCupDirectory :: GHCupPath -> FilePath -> IO GHCupPath+createTempGHCupDirectory (GHCupPath gp) d = GHCupPath <$> createTempDirectory gp d+++getGHCupTmpDirs :: IO [GHCupPath]+getGHCupTmpDirs = do+  tmpdir <- fromGHCupPath <$> ghcupTMPDir+  ghcup_dirs <- handleIO (\_ -> pure []) $ findFiles+    tmpdir+    (makeRegexOpts compExtended+                   execBlank+                   ([s|^ghcup-.*$|] :: ByteString)+    )+  pure (fmap (\p -> GHCupPath (tmpdir </> p)) $ filter (maybe False ("ghcup-" `isPrefixOf`) . lastMay . splitPath) ghcup_dirs)+++    ------------------------------+    --[ GHCup base directories ]--+    ------------------------------+++-- | ~/.ghcup by default+--+-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),+-- then uses 'XDG_DATA_HOME/ghcup' as per xdg spec.+ghcupBaseDir :: IO GHCupPath+ghcupBaseDir+  | isWindows = do+      bdir <- fromMaybe "C:\\" <$> lookupEnv "GHCUP_INSTALL_BASE_PREFIX"+      pure (GHCupPath (bdir </> "ghcup"))+  | otherwise = do+      xdg <- useXDG+      if xdg+        then do+          bdir <- lookupEnv "XDG_DATA_HOME" >>= \case+            Just r  -> pure r+            Nothing -> do+              home <- liftIO getHomeDirectory+              pure (home </> ".local" </> "share")+          pure (GHCupPath (bdir </> "ghcup"))+        else do+          bdir <- lookupEnv "GHCUP_INSTALL_BASE_PREFIX" >>= \case+            Just r  -> pure r+            Nothing -> liftIO getHomeDirectory+          pure (GHCupPath (bdir </> ".ghcup"))+++-- | ~/.ghcup by default+--+-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),+-- then uses 'XDG_CONFIG_HOME/ghcup' as per xdg spec.+ghcupConfigDir :: IO GHCupPath+ghcupConfigDir+  | isWindows = ghcupBaseDir+  | otherwise = do+      xdg <- useXDG+      if xdg+        then do+          bdir <- lookupEnv "XDG_CONFIG_HOME" >>= \case+            Just r  -> pure r+            Nothing -> do+              home <- liftIO getHomeDirectory+              pure (home </> ".config")+          pure (GHCupPath (bdir </> "ghcup"))+        else do+          bdir <- lookupEnv "GHCUP_INSTALL_BASE_PREFIX" >>= \case+            Just r  -> pure r+            Nothing -> liftIO getHomeDirectory+          pure (GHCupPath (bdir </> ".ghcup"))+++-- | If 'GHCUP_USE_XDG_DIRS' is set (to anything),+-- then uses 'XDG_BIN_HOME' env var or defaults to '~/.local/bin'+-- (which, sadly is not strictly xdg spec).+ghcupBinDir :: IO FilePath+ghcupBinDir+  | isWindows = (fromGHCupPath <$> ghcupBaseDir) <&> (</> "bin")+  | otherwise = do+      xdg <- useXDG+      if xdg+        then do+          lookupEnv "XDG_BIN_HOME" >>= \case+            Just r  -> pure r+            Nothing -> do+              home <- liftIO getHomeDirectory+              pure (home </> ".local" </> "bin")+        else (fromGHCupPath <$> ghcupBaseDir) <&> (</> "bin")+++-- | Defaults to '~/.ghcup/cache'.+--+-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),+-- then uses 'XDG_CACHE_HOME/ghcup' as per xdg spec.+ghcupCacheDir :: IO GHCupPath+ghcupCacheDir+  | isWindows = ghcupBaseDir <&> (\(GHCupPath gp) -> GHCupPath (gp </> "cache"))+  | otherwise = do+      xdg <- useXDG+      if xdg+        then do+          bdir <- lookupEnv "XDG_CACHE_HOME" >>= \case+            Just r  -> pure r+            Nothing -> do+              home <- liftIO getHomeDirectory+              pure (home </> ".cache")+          pure (GHCupPath (bdir </> "ghcup" </> "cache"))+        else ghcupBaseDir <&> (\(GHCupPath gp) -> GHCupPath (gp </> "cache"))+++-- | Defaults to '~/.ghcup/logs'.+--+-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),+-- then uses 'XDG_STATE_HOME/ghcup/logs' as per xdg spec.+ghcupLogsDir :: IO GHCupPath+ghcupLogsDir+  | isWindows = ghcupBaseDir <&> (\(GHCupPath gp) -> GHCupPath (gp </> "logs"))+  | otherwise = do+      xdg <- useXDG+      if xdg+        then do+          bdir <- lookupEnv "XDG_STATE_HOME" >>= \case+            Just r  -> pure r+            Nothing -> do+              home <- liftIO getHomeDirectory+              pure (home </> ".local" </> "state")+          pure (GHCupPath (bdir </> "ghcup" </> "logs"))+        else ghcupBaseDir <&> (\(GHCupPath gp) -> GHCupPath (gp </> "logs"))+++-- | Defaults to '~/.ghcup/db.+--+-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),+-- then uses 'XDG_CACHE_HOME/ghcup/db as per xdg spec.+ghcupDbDir :: IO GHCupPath+ghcupDbDir = ghcupBaseDir <&> (\(GHCupPath gp) -> GHCupPath (gp </> "db"))+++-- | '~/.ghcup/trash'.+-- Mainly used on windows to improve file removal operations+ghcupRecycleDir :: IO GHCupPath+ghcupRecycleDir = ghcupBaseDir <&> (\(GHCupPath gp) -> GHCupPath (gp </> "trash"))+++-- | Defaults to '~/.ghcup/tmp.+--+-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),+-- then uses 'XDG_CACHE_HOME/ghcup/tmp as per xdg spec.+ghcupTMPDir :: IO GHCupPath+ghcupTMPDir+  | isWindows = ghcupBaseDir <&> (\(GHCupPath gp) -> GHCupPath (gp </> "tmp"))+  | otherwise = do+      xdg <- useXDG+      if xdg+        then do+          bdir <- lookupEnv "XDG_CACHE_HOME" >>= \case+            Just r  -> pure r+            Nothing -> do+              home <- liftIO getHomeDirectory+              pure (home </> ".cache")+          pure (GHCupPath (bdir </> "ghcup" </> "tmp"))+        else ghcupBaseDir <&> (\(GHCupPath gp) -> GHCupPath (gp </> "tmp"))+++ghcupMsys2Dir :: IO FilePath+ghcupMsys2Dir =+  lookupEnv "GHCUP_MSYS2" >>= \case+    Just fp -> pure fp+    Nothing -> do+      baseDir <- liftIO ghcupBaseDir+      pure (fromGHCupPath baseDir </> "msys64")++ghcupMsys2BinDirs :: (MonadFail m, MonadIO m, MonadReader env m, HasDirs env) => m [FilePath]+ghcupMsys2BinDirs = do+  Dirs{..} <- getDirs+  liftIO $ ghcupMsys2BinDirs_ msys2Dir++ghcupMsys2BinDirs' :: IO [FilePath]+ghcupMsys2BinDirs' = do+  msys2Dir <- ghcupMsys2Dir+  ghcupMsys2BinDirs_ msys2Dir++ghcupMsys2BinDirs_ :: FilePath -> IO [FilePath]+ghcupMsys2BinDirs_ msys2Dir' = do+  env <- liftIO (lookupEnv "GHCUP_MSYS2_ENV") >>= \case+    Just env -> maybe (fail parseFailMsg) pure $ readMay @MSYS2Env env+    Nothing+      | "x86_64"  <- arch -> pure MINGW64+      | "i386"    <- arch -> pure MINGW32+      | "aarch64" <- arch -> pure CLANGARM64+      | otherwise -> fail "No compatible architecture for msys2"+  pure [msys2Dir' </> toEnvDir env </> "bin", msys2Dir' </> toEnvDir MSYS </> "bin"]+ where+  -- https://www.msys2.org/docs/environments/+  toEnvDir :: MSYS2Env -> FilePath+  toEnvDir MSYS       = "usr"+  toEnvDir UCRT64     = "ucrt64"+  toEnvDir CLANG64    = "clang64"+  toEnvDir CLANGARM64 = "clangarm64"+  toEnvDir CLANG32    = "clang32"+  toEnvDir MINGW64    = "mingw64"+  toEnvDir MINGW32    = "mingw32"++  parseFailMsg = "Invalid value for GHCUP_MSYS2_ENV. Valid values are: MSYS, UCRT64, CLANG64, CLANGARM64, CLANG32, MINGW64, MINGW32"+++getAllDirs :: IO Dirs+getAllDirs = do+  baseDir    <- ghcupBaseDir+  binDir     <- ghcupBinDir+  cacheDir   <- ghcupCacheDir+  logsDir    <- ghcupLogsDir+  confDir    <- ghcupConfigDir+  recycleDir <- ghcupRecycleDir+  tmpDir     <- ghcupTMPDir+  dbDir      <- ghcupDbDir+  msys2Dir   <- ghcupMsys2Dir+  pure Dirs { .. }++++    -------------------+    --[ GHCup files ]--+    -------------------++getConfigFilePath :: (MonadIO m) => m FilePath+getConfigFilePath = do+  confDir <- liftIO ghcupConfigDir+  pure $ fromGHCupPath confDir </> "config.yaml"++getConfigFilePath' :: (MonadReader env m, HasDirs env) => m FilePath+getConfigFilePath' = do+  Dirs {..} <- getDirs+  pure $ fromGHCupPath confDir </> "config.yaml"+++ghcupConfigFile :: (MonadIO m)+                => Excepts '[JSONError] m UserSettings+ghcupConfigFile = do+  filepath <- getConfigFilePath+  contents <- liftIO $ handleIO (\e -> if NoSuchThing == ioeGetErrorType e then pure Nothing else liftIO $ ioError e) $ Just <$> BS.readFile filepath+  case contents of+      Nothing -> pure defaultUserSettings+      Just contents' -> liftE+        . veitherToExcepts @_ @'[JSONError]+        . either (VLeft . V) VRight+        . first (JSONDecodeError . displayException)+        . Y.decodeEither'+        $ contents'+++    -------------------------+    --[ GHCup directories ]--+    -------------------------+++-- | ~/.ghcup/ghc by default.+ghcupGHCBaseDir :: (MonadReader env m, HasDirs env) => m GHCupPath+ghcupGHCBaseDir = do+  Dirs {..}  <- getDirs+  pure (baseDir `appendGHCupPath` "ghc")++-- | The install dir for a tool is simply determined by its tool name+-- and version.+toolInstallDestination :: (MonadReader env m, HasDirs env)+                       => Tool+                       -> TargetVersion+                       -> m GHCupPath+toolInstallDestination tool ver = do+  bDir  <- toolBaseDir tool+  pure (bDir `appendGHCupPath` prettyShow ver)++toolBaseDir ::+  (MonadReader env m, HasDirs env)+  => Tool+  -> m GHCupPath+toolBaseDir tool = do+  Dirs {..}  <- getDirs+  pure (baseDir `appendGHCupPath` prettyShow tool)++-- | Gets '~/.ghcup/ghc/<ghcupGHCDir>'.+-- The dir may be of the form+--   * armv7-unknown-linux-gnueabihf-8.8.3+--   * 8.8.4+ghcupGHCDir :: (MonadReader env m, HasDirs env, MonadThrow m)+            => TargetVersion+            -> m GHCupPath+ghcupGHCDir ver = do+  ghcbasedir <- ghcupGHCBaseDir+  let verdir = T.unpack $ tVerToText ver+  pure (ghcbasedir `appendGHCupPath` verdir)+++-- | See 'ghcupToolParser'.+parseGHCupGHCDir :: MonadThrow m => FilePath -> m TargetVersion+parseGHCupGHCDir (T.pack -> fp) =+  throwEither $ MP.parse ghcTargetVerP "" fp++parseGHCupHLSDir :: MonadThrow m => FilePath -> m Version+parseGHCupHLSDir (T.pack -> fp) =+  throwEither $ MP.parse version' "" fp++-- TODO: inlined from GHCup.Prelude+throwEither :: (Exception a, MonadThrow m) => Either a b -> m b+throwEither a = case a of+  Left  e -> throwM e+  Right r -> pure r++-- | ~/.ghcup/hls by default, for new-style installs.+ghcupHLSBaseDir :: (MonadReader env m, HasDirs env) => m GHCupPath+ghcupHLSBaseDir = do+  Dirs {..}  <- getDirs+  pure (baseDir `appendGHCupPath` "hls")++-- | Gets '~/.ghcup/hls/<hls-ver>' for new-style installs.+ghcupHLSDir :: (MonadReader env m, HasDirs env, MonadThrow m)+            => Version+            -> m GHCupPath+ghcupHLSDir ver = do+  basedir <- ghcupHLSBaseDir+  let verdir = T.unpack $ prettyVer ver+  pure (basedir `appendGHCupPath` verdir)+++mkGhcupTmpDir :: ( MonadReader env m+                 , HasDirs env+                 , MonadUnliftIO m+                 , HasLog env+                 , MonadCatch m+                 , MonadThrow m+                 , MonadMask m+                 , MonadIO m)+              => m GHCupPath+mkGhcupTmpDir = GHCupPath <$> do+  Dirs { tmpDir } <- getDirs+  liftIO $ createTempDirectory (fromGHCupPath tmpDir) "ghcup"+++withGHCupTmpDir :: ( MonadReader env m+                   , HasDirs env+                   , HasLog env+                   , HasSettings env+                   , MonadUnliftIO m+                   , MonadCatch m+                   , MonadResource m+                   , MonadThrow m+                   , MonadMask m+                   , MonadIO m)+                => m GHCupPath+withGHCupTmpDir = do+  Settings{keepDirs} <- getSettings+  snd <$> withRunInIO (\run ->+    run+      $ allocate+          (run mkGhcupTmpDir)+          (\fp -> if -- we don't know whether there was a failure, so can only+                     -- decide for 'Always'+                     | keepDirs == Always -> pure ()+                     | otherwise -> handleIO (\e -> run+                        $ logDebug ("Resource cleanup failed for "+                                   <> T.pack (fromGHCupPath fp)+                                   <> ", error was: "+                                   <> T.pack (displayException e)))+                        . removePathForcibly+                        $ fp))+++++    --------------+    --[ Others ]--+    --------------+++useXDG :: IO Bool+useXDG = isJust <$> lookupEnv "GHCUP_USE_XDG_DIRS"+++-- | Like 'relpath'. Assumes the inputs are resolved in case of symlinks.+relativeSymlink :: FilePath  -- ^ the path in which to create the symlink+                -> FilePath  -- ^ the symlink destination+                -> FilePath+relativeSymlink p1 p2+  | isWindows = p2 -- windows quickly gets into MAX_PATH issues so we don't care about relative symlinks+  | otherwise =+    let d1      = splitDirectories p1+        d2      = splitDirectories p2+        common  = takeWhile (\(x, y) -> x == y) $ zip d1 d2+        cPrefix = drop (length common) d1+    in  joinPath (replicate (length cPrefix) "..")+          <> joinPath ([pathSeparator] : drop (length common) d2)+++cleanupTrash :: ( MonadIO m+                , MonadMask m+                , MonadReader env m+                , HasLog env+                , HasDirs env+                , HasSettings env+                )+             => m ()+cleanupTrash = do+  Dirs { recycleDir } <- getDirs+  contents <- liftIO $ listDirectory (fromGHCupPath recycleDir)+  if null contents+  then pure ()+  else do+    logWarn ("Removing leftover files in " <> T.pack (fromGHCupPath recycleDir))+    forM_ contents (\fp -> handleIO (\e ->+        logDebug ("Resource cleanup failed for " <> T.pack fp <> ", error was: " <> T.pack (displayException e))+      ) $ liftIO $ removePathForcibly (recycleDir `appendGHCupPath` fp))+++-- | List *actual files* in a directory, ignoring empty files and a couple+-- of blacklisted files, such as '.DS_Store' on mac.+listDirectoryFiles :: FilePath -> IO [FilePath]+listDirectoryFiles fp = do+  listDirectory fp >>= filterM (doesFileExist . (fp </>)) <&> filter (\fp' -> not (isHidden fp') && not (isBlacklisted fp'))++-- | List *actual directories* in a directory, ignoring empty directories and a couple+-- of blacklisted files, such as '.DS_Store' on mac.+listDirectoryDirs :: FilePath -> IO [FilePath]+listDirectoryDirs fp = do+  listDirectory fp >>= filterM (doesDirectoryExist . (fp </>)) <&> filter (\fp' -> not (isHidden fp') && not (isBlacklisted fp'))++isHidden :: FilePath -> Bool+isHidden fp'+  | isWindows = False+  | Just ('.', _) <- uncons fp' = True+  | otherwise = False++isBlacklisted :: FilePath -> Bool+{- HLINT ignore "Use ==" -}+isBlacklisted fp' = fp' `elem` [".DS_Store"]++++-- System.Directory re-exports with GHCupPath++removeDirectory :: GHCupPath -> IO ()+removeDirectory (GHCupPath fp) = SD.removeDirectory fp++removeDirectoryRecursive :: GHCupPath -> IO ()+removeDirectoryRecursive (GHCupPath fp) = SD.removeDirectoryRecursive fp++removePathForcibly :: GHCupPath -> IO ()+removePathForcibly (GHCupPath fp) = SD.removePathForcibly fp+
+ lib/GHCup/Query/GHCupDirs.hs-boot view
@@ -0,0 +1,37 @@+module GHCup.Query.GHCupDirs+ ( GHCupPath+ , appendGHCupPath+ , fromGHCupPath+ , createTempGHCupDirectory+ , removeDirectory+ , removeDirectoryRecursive+ , removePathForcibly+ )+ where++import Control.DeepSeq (NFData)+++-- | A 'GHCupPath' is a safe sub-path that can be recursively deleted.+newtype GHCupPath = GHCupPath FilePath++instance Show GHCupPath where++instance Eq GHCupPath where++instance Ord GHCupPath where++instance NFData GHCupPath where++appendGHCupPath :: GHCupPath -> FilePath -> GHCupPath++fromGHCupPath :: GHCupPath -> FilePath++createTempGHCupDirectory :: GHCupPath -> FilePath -> IO GHCupPath++removeDirectory :: GHCupPath -> IO ()++removeDirectoryRecursive :: GHCupPath -> IO ()++removePathForcibly :: GHCupPath -> IO ()+
+ lib/GHCup/Query/Metadata.hs view
@@ -0,0 +1,362 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleContexts #-}++{-|+Module      : GHCup.Query.Metadata+Description : Queries on GHCup metadata and its data+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Query.Metadata where++import GHCup.Errors+import GHCup.Prelude.Version+import GHCup.Types+import GHCup.Types.JSON+    ()+import GHCup.Types.Optics++import Control.Applicative+import Control.Monad.Catch  ( MonadThrow )+import Control.Monad.Reader ( MonadReader )+import Data.List            ( find )+import Data.Maybe+import Data.Text            ( Text )+import Data.Time            ( Day, addDays, diffDays )+import Data.Variant.Excepts ( Excepts, throwE, liftE )+import Data.Versions        ( PVP )+import Optics+import Prelude              hiding ( readFile, writeFile )+import Safe                 ( headMay, lastMay )+import URI.ByteString       ( URI )++import qualified Data.Map.Strict as M+import qualified Data.Map.Strict as Map+import qualified Data.Text       as T+import Control.Monad.Trans (lift)+import Control.Monad (guard)+import GHCup.Prelude++++    --------------------+    --[ Requirements ]--+    --------------------+++getDownloadInfoE ::+  ( MonadReader env m+  , HasPlatformReq env+  , HasGHCupInfo env+  )+  => Tool+  -> VersionReq+  -- ^ tool version+  -> Excepts+       '[NoDownload]+       m+       (Int, DownloadInfo)+getDownloadInfoE t VersionReq{..} = getDownloadInfoE' t (TargetVersionReq (mkTVer _vqVersion) _vqRev)+++getDownloadInfoE' ::+  ( MonadReader env m+  , HasPlatformReq env+  , HasGHCupInfo env+  )+  => Tool+  -> TargetVersionReq+  -- ^ tool version+  -> Excepts+       '[NoDownload]+       m+       (Int, DownloadInfo)+getDownloadInfoE' t tvr = do+  pfreq <- lift getPlatformReq+  ghcupInfo <- lift getGHCupInfo+  lE $ getDownloadInfo t tvr ghcupInfo pfreq+++getDownloadInfo ::+     Tool+  -> TargetVersionReq+  -> GHCupInfo+  -> PlatformRequest+  -> Either NoDownload (Int, DownloadInfo)+getDownloadInfo t tvr@TargetVersionReq{..} (GHCupInfo { _ghcupDownloads = dls }) pfreq =+  let mRev_Vi = preview (_GHCupDownloads+                        % ix t+                        % toolVersionsL+                        % ix _tvqTargetVer+                        % revisionSpecL+                        % ixOrLast _tvqRev+                        ) dls+  in maybe (Left $ NoDownload tvr t (Just pfreq)) Right (mRev_Vi >>= \(rev, vi) -> (rev,) <$> getDownloadInfo' pfreq vi)+++getDownloadInfo' ::+     PlatformRequest+  -> VersionInfo+  -> Maybe DownloadInfo+getDownloadInfo' (PlatformRequest a p mv) vi =+  let distro_preview f g =+        let platformVersionSpec = preview+                                      ( archL+                                      % to unMapIgnoreUnknownKeys+                                      % ix a+                                      % _PlatformSpec+                                      % to unMapIgnoreUnknownKeys+                                      % ix (f p)+                                      % _PlatformVersionSpec+                                      ) vi+            mv' = g mv+        in  (\m ->+                fmap snd+              . find+                  (\(mverRange, _) -> maybe+                     (isNothing mv')+                     (\range -> maybe False (`versionRange` range) mv')+                     mverRange+                  )+              . M.toList+              $ m+            ) =<< platformVersionSpec+      with_distro        = distro_preview id id+      without_distro_ver = distro_preview id (const Nothing)+      without_distro     = distro_preview (set _Linux UnknownLinux) (const Nothing)++  in case p of+       -- non-musl won't work on alpine+       Linux Alpine -> with_distro <|> without_distro_ver+       _            -> with_distro <|> without_distro_ver <|> without_distro+++    --------------------+    --[ Requirements ]--+    --------------------++-- | Get the requirements. Right now this combines GHC and cabal+-- and doesn't do fine-grained distinction. However, the 'ToolRequirements'+-- type allows it.+getCommonRequirements :: Tool+                      -> PlatformResult+                      -> ToolRequirements+                      -> Maybe Requirements+getCommonRequirements tool pr tr =+  with_distro <|> without_distro_ver <|> without_distro+ where+  with_distro        = distro_preview _platform _distroVersion+  without_distro_ver = distro_preview _platform (const Nothing)+  without_distro     = distro_preview (set _Linux UnknownLinux . _platform) (const Nothing)++  distro_preview f g =+    let platformVersionSpec =+          preview (ix tool % ix Nothing % to unMapIgnoreUnknownKeys % ix (f pr)) tr+        mv' = g pr+    in  fmap snd+          .   find+                (\(mverRange, _) -> maybe+                  (isNothing mv')+                  (\range -> maybe False (`versionRange` range) mv')+                  mverRange+                )+          .   M.toList+          =<< platformVersionSpec+++prettyRequirements :: Requirements -> T.Text+prettyRequirements Requirements {..} =+  let d = if not . null $ _distroPKGs+        then "\n  Please ensure the following distro packages "+          <> "are installed before continuing (you can exit ghcup "+          <> "and return at any time): "+          <> "\n    "+          <> T.intercalate " " _distroPKGs+        else ""+      n = if not . T.null $ _notes then "\n  Note: " <> _notes else ""+  in  "System requirements " <> d <> n++rawRequirements :: Requirements -> T.Text+rawRequirements Requirements {..} =+  if not . null $ _distroPKGs+  then T.intercalate " " _distroPKGs+  else ""++++    ----------------+    --[ Versions ]--+    ----------------+++-- | Get the latest available ghc for the given PVP version, which+-- may only contain parts.+--+-- >>> (fmap . fmap) (\(p, _, _) -> p) $ getLatestToolFor GHC Nothing [pver|8|] r+-- Just (PVP {_pComponents = 8 :| [10,7]})+-- >>> (fmap . fmap) (\(p, _, _) -> p) $ getLatestToolFor GHC Nothing [pver|8.8|] r+-- Just (PVP {_pComponents = 8 :| [8,4]})+-- >>> (fmap . fmap) (\(p, _, _) -> p) $ getLatestToolFor GHC Nothing [pver|8.8.4|] r+-- Just (PVP {_pComponents = 8 :| [8,4]})+getLatestToolFor :: MonadThrow m+                 => Tool+                 -> Maybe Text+                 -> PVP+                 -> GHCupDownloads+                 -> m (Maybe (PVP, VersionMetadata, Maybe Text))+getLatestToolFor tool target pvpIn dls = do+  let ls :: [(TargetVersion, VersionMetadata)]+      ls = fromMaybe [] $ preview (_GHCupDownloads % ix tool % toolVersionsL % to Map.toDescList) dls+  let ps :: [(PVP, VersionMetadata, Maybe Text)]+      ps = catMaybes $ fmap (\(v, vm) -> do+             (pvp, unparsable) <- versionToPVP (_tvVersion v)+             guard (T.null unparsable) -- TODO: hm+             pure (pvp, vm, _tvTarget v)+           ) ls+  pure . headMay . filter (\(v, _, t) -> matchPVPrefix pvpIn v && t == target) $ ps+++    ------------+    --[ Tags ]--+    ------------+++selectLatestRevL :: Getter ToolVersionSpec (M.Map TargetVersion (Int, VersionInfo))+selectLatestRevL = _ToolVersionSpec % to (M.mapMaybe (lastMay . Map.toAscList . Map.mapKeys unRev . unRevisionSpec . _vmRevisionSpec))++selectRevL :: Maybe Int -> AffineFold VersionMetadata (Int, VersionInfo)+selectRevL mrev = revisionSpecL % ixOrLast mrev++-- | Get the tool version that has this tag. If multiple have it,+-- picks the greatest version.+getTaggedL' :: Tag+            -> Lens' a [Tag]+            -> Fold (Map.Map TargetVersion a) (TargetVersion, a)+getTaggedL' tag getTags =+  to (Map.toDescList . Map.filter (\a -> tag `elem` fromMaybe [] (preview getTags a)))+  % folding id++getTaggedL :: Tag+           -> Fold ToolVersionSpec (TargetVersion, VersionMetadata)+getTaggedL tag = _ToolVersionSpec % getTaggedL' tag vmTags++getFirstTag :: Tag -> GHCupDownloads -> Tool -> Maybe TargetVersion+getFirstTag tag av tool = do+  (tv, _) <- headOf (_GHCupDownloads % ix tool % toolVersions % getTaggedL tag) av+  pure tv++getRev :: GHCupDownloads -> Tool -> TargetVersion -> Maybe Int -> Maybe (VersionMetadata, Int, VersionInfo)+getRev av tool tv mRev = do+  vm <- preview (_GHCupDownloads % ix tool % toolVersionsL % ix tv) av+  (rev, vi) <- preview (selectRevL mRev) vm+  pure (vm, rev, vi)++getByReleaseDay :: GHCupDownloads -> Tool -> Day -> Either (Maybe Day) (TargetVersion, VersionMetadata)+getByReleaseDay av tool day =+  let mvv = fromMaybe mempty $ headOf (_GHCupDownloads % ix tool % toolVersions % _ToolVersionSpec) av+      mdv = Map.foldrWithKey (\k vi@VersionMetadata{..} m ->+                maybe m (\d -> let diff = diffDays d day+                               in Map.insert (abs diff) (diff, (k, vi)) m) _vmReleaseDay)+              Map.empty+              mvv+  in case headMay (Map.toAscList mdv) of+       Nothing -> Left Nothing+       Just (absDiff, (diff, (k, vi)))+         | absDiff == 0 -> Right (k, vi)+         | otherwise -> Left (Just (addDays diff day))++getByReleaseDayFold :: Day -> Fold (Map.Map TargetVersion VersionMetadata) TargetVersion+getByReleaseDayFold day = to (fmap fst . Map.toDescList . Map.filter (\VersionMetadata {..} -> Just day == _vmReleaseDay)) % folding id++getLatest :: GHCupDownloads -> Tool -> Maybe TargetVersion+getLatest = getFirstTag Latest++getLatestPrerelease :: GHCupDownloads -> Tool -> Maybe TargetVersion+getLatestPrerelease = getFirstTag LatestPrerelease++getLatestNightly :: GHCupDownloads -> Tool -> Maybe TargetVersion+getLatestNightly = getFirstTag LatestNightly++getRecommended :: GHCupDownloads -> Tool -> Maybe TargetVersion+getRecommended = getFirstTag Recommended++-- | Gets the latest GHC with a given base version.+getLatestBaseVersion :: GHCupDownloads -> PVP -> Maybe TargetVersion+getLatestBaseVersion g pvpVer = getFirstTag (Base pvpVer) g ghc+++getVersionMetadata :: TargetVersion+                   -> Tool+                   -> GHCupDownloads+                   -> Maybe VersionMetadata+getVersionMetadata v' tool =+  headOf+    ( _GHCupDownloads+    % ix tool+    % toolVersions+    % _ToolVersionSpec+    % to (Map.filterWithKey (\k _ -> k == v'))+    % to Map.elems+    % _head+    )+++    -----------------+    --[ Changelog ]--+    -----------------+++getChangeLog :: GHCupDownloads -> Tool -> TargetVersion -> Maybe URI+getChangeLog dls tool tv =+  preview (_GHCupDownloads % ix tool % toolVersionsL % ix tv % vmChangeLog % _Just) dls++++    -------------+    --[ Other ]--+    -------------+++-- NOTE: there might be installed tools that are not in the available tools set+-- (e.g. because the metadata was removed)+allAvailableTools :: GHCupDownloads -> [(Tool, [(TargetVersion, VersionMetadata)])]+allAvailableTools = Map.toList . Map.mapWithKey (\_ (ToolInfo (ToolVersionSpec v) _) -> Map.toList v) . unGHCupDownloads++installationSpecFromMetadata' ::+  ( MonadReader env m+  , HasPlatformReq env+  )+  => DownloadInfo+  -> Tool+  -> TargetVersion+  -> Excepts '[NoInstallInfo] m InstallationSpecInput+installationSpecFromMetadata' dlinfo tool tver = do+  pfreq <- lift getPlatformReq+  case _dlInstallSpec dlinfo of+    Just installInfo -> pure installInfo+    Nothing+     | Just i <- toInstallationInputSpec <$> defaultToolInstallSpec tool pfreq tver+     -> pure i+     | otherwise+     -> throwE $ NoInstallInfo tool tver++-- has defaults, so works with legacy metadata+installationSpecFromMetadata ::+  ( MonadReader env m+  , HasGHCupInfo env+  , HasPlatformReq env+  )+  => Tool+  -> TargetVersionReq+  -> Excepts '[NoDownload, NoInstallInfo] m (Int, InstallationSpecInput)+installationSpecFromMetadata tool tver = do+  pfreq <- lift getPlatformReq+  ghcupInfo <- lift getGHCupInfo+  (rev, dlinfo) <- lE $ getDownloadInfo tool tver ghcupInfo pfreq+  spec <- liftE $ installationSpecFromMetadata' dlinfo tool (_tvqTargetVer tver)+  pure (rev, spec)+
+ lib/GHCup/Query/Symlink.hs view
@@ -0,0 +1,133 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}++module GHCup.Query.Symlink where++import GHCup.Errors+import GHCup.Legacy.Utils+import GHCup.Prelude+import GHCup.Types+import GHCup.Types.Optics++import Control.Exception      ( Exception (..) )+import Control.Exception.Safe ( handle )+import Control.Monad          ( forM, when )+import Control.Monad.Reader   ( MonadReader )+import Data.Either            ( partitionEithers )+import Data.Maybe             ( catMaybes )+import Data.Variant.Excepts   ( Excepts, throwE )+import Data.Versions          ( Version, prettyVer )+import System.FilePath        ( (</>) )++import qualified Data.Text as T+++-- | These are the symlinks we need to create+-- in order to 'set' a tool version.+getUnqualifiedSymlinks ::+  ( MonadReader env m+  , HasDirs env+  , HasLog env+  , MonadIOish m+  )+  => [SymlinkFileSpec]+  -> FilePath+  -> m [(FilePath, FilePath)]+getUnqualifiedSymlinks specs toolDir = do+  Dirs {..}  <- getDirs+  getUnqualifiedSymlinks' binDir specs toolDir++-- | Like 'getUnqualifiedSymlinks', except takes+-- the binary directory as an explicit argument.+getUnqualifiedSymlinks' ::+  ( MonadReader env m+  , HasDirs env+  , HasLog env+  , MonadIOish m+  )+  => FilePath+  -> [SymlinkFileSpec]+  -> FilePath+  -> m [(FilePath, FilePath)]+getUnqualifiedSymlinks' bindir specs toolDir =+  fmap catMaybes $ forM specs $ \SymlinkSpec{..} ->+    case _slSetName of+      Nothing -> pure Nothing+      Just setName -> do+       target <- binarySymLinkDestination bindir (toolDir </> _slTarget)+       pure $ Just (target, bindir </> setName)++getPVPMajorSymlinks' ::+  ( MonadReader env m+  , HasLog env+  , MonadIOish m+  )+  => FilePath+  -> [SymlinkSpec [Either Char Version]]+  -> Version+  -> FilePath+  -> Excepts '[MalformedInstallInfo] m [(FilePath, FilePath)]+getPVPMajorSymlinks' bindir spec ver toolBinDir =+  fmap catMaybes $ forM spec $ \SymlinkSpec{..} -> do+    if _slPVPMajorLinks+    then do+      let target = mconcat $ either (:[]) (T.unpack . prettyVer) <$> _slTarget+      targetResolved <- binarySymLinkDestination bindir (toolBinDir </> target)+      handle+          (\(e :: ParseError) -> logWarn (T.pack $ displayException e) >> pure Nothing)+        $ do+          when (null . snd . partitionEithers $ _slLinkName) $ throwE $ MalformedInstallInfo "No ${PKGVER} found in linkName"+          (mj, mi) <- getMajorMinorV ver+          let major' = T.unpack (intToText mj <> "." <> intToText mi)+              link_name = mconcat $ either (:[]) (const major') <$> _slLinkName+          logDebug2 $ T.pack (show _slLinkName)+          logDebug2 $ T.pack (show link_name)+          logDebug2 $ T.pack (show major')++          -- if our tool has only two components anyway, we skip this+          if (intToText mj <> "." <> intToText mi) == prettyVer ver+          then pure Nothing+          else pure (Just (targetResolved, bindir </> link_name))+    else pure Nothing++getPVPMajorSymlinks ::+  ( MonadReader env m+  , HasDirs env+  , HasLog env+  , MonadIOish m+  )+  => [SymlinkSpec [Either Char Version]]+  -> Version+  -> FilePath+  -> Excepts '[MalformedInstallInfo] m [(FilePath, FilePath)]+getPVPMajorSymlinks specs ver toolBinDir = do+  Dirs {..}  <- getDirs+  getPVPMajorSymlinks' binDir specs ver toolBinDir++getPVPSymlinks' ::+  ( MonadReader env m+  , HasLog env+  , MonadIOish m+  )+  => FilePath+  -> [SymlinkFileSpec]+  -> FilePath+  -> m [(FilePath, FilePath)]+getPVPSymlinks' bindir specs toolDir = do+  forM specs $ \SymlinkSpec{..} -> do+      target <- binarySymLinkDestination bindir (toolDir </> _slTarget)+      pure (target, bindir </> _slLinkName)++getPVPSymlinks ::+  ( MonadReader env m+  , HasDirs env+  , HasLog env+  , MonadIOish m+  )+  => [SymlinkFileSpec]+  -> FilePath+  -> m [(FilePath, FilePath)]+getPVPSymlinks specs toolDir = do+  Dirs {..}  <- getDirs+  getPVPSymlinks' binDir specs toolDir
+ lib/GHCup/Query/System.hs view
@@ -0,0 +1,371 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskellQuotes #-}+++{-|+Module      : GHCup.Query.System+Description : Retrieving platform information+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Query.System where+++import GHCup.Errors+import GHCup.Prelude+import GHCup.Prelude.MegaParsec+import GHCup.Prelude.Process+import GHCup.Prelude.String.QQ+import GHCup.Prelude.Version.QQ+import GHCup.System.Directory+import GHCup.Types+import GHCup.Types.JSON+    ()+import GHCup.Types.Optics++#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ( MonadFail )+#endif+import Control.Applicative+import Control.Exception.Safe+import Control.Monad+import Control.Monad.Reader+import Data.ByteString                ( ByteString )+import Data.Foldable+import Data.Maybe+import Data.Text                      ( Text )+import Data.Variant.Excepts+import Data.Versions+import Prelude                        hiding ( abs, readFile, writeFile )+import System.Exit+import System.FilePath+import System.Info+import System.OsRelease               as OSR+import Text.PrettyPrint.HughesPJClass ( prettyShow )+import Text.Regex.Posix++import qualified Text.Megaparsec as MP++import qualified Data.List    as L+import qualified Data.Text    as T+import qualified Data.Text.IO as T+import           Data.Void+++++    --------------------------+    --[ Platform detection ]--+    --------------------------+++-- | Get the full platform request, consisting of architecture, distro, ...+platformRequest :: (MonadReader env m, MonadFail m, HasLog env, MonadCatch m, MonadIO m)+                => Excepts+                     '[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound]+                     m+                     PlatformRequest+platformRequest = do+  (PlatformResult rp rv) <- liftE getPlatform+  ar                     <- lE getArchitecture+  pure $ PlatformRequest ar rp rv+++getArchitecture :: Either NoCompatibleArch Architecture+getArchitecture = case arch of+  "x86_64"      -> Right A_64+  "i386"        -> Right A_32+  "powerpc"     -> Right A_PowerPC+  "powerpc64"   -> Right A_PowerPC64+  "powerpc64le" -> Right A_PowerPC64+  "sparc"       -> Right A_Sparc+  "sparc64"     -> Right A_Sparc64+  "arm"         -> Right A_ARM+  "aarch64"     -> Right A_ARM64+  what          -> Left (NoCompatibleArch what)+++getPlatform :: (MonadReader env m, HasLog env, MonadCatch m, MonadIO m, MonadFail m)+            => Excepts+                 '[NoCompatiblePlatform, DistroNotFound]+                 m+                 PlatformResult+getPlatform = do+  pfr <- case os of+    "linux" -> do+      (distro, ver) <- liftE getLinuxDistro+      pure $ PlatformResult { _platform = Linux distro, _distroVersion = ver }+    "darwin" -> do+      ver <-+        either (const Nothing) Just+          . versioning+          -- TODO: maybe do this somewhere else+          . decUTF8Safe'+        <$> getDarwinVersion+      pure $ PlatformResult { _platform = Darwin, _distroVersion = ver }+    "freebsd" -> do+      ver <-+        either (const Nothing) Just . versioning . decUTF8Safe'+          <$> getFreeBSDVersion+      pure $ PlatformResult { _platform = FreeBSD, _distroVersion = ver }+    "openbsd" -> do+      ver <-+        either (const Nothing) Just . versioning . decUTF8Safe'+          <$> getOpenBSDVersion+      pure $ PlatformResult { _platform = OpenBSD, _distroVersion = ver }+    "mingw32" -> pure PlatformResult { _platform = Windows, _distroVersion = Nothing }+    what -> throwE $ NoCompatiblePlatform what+  lift $ logDebug $ "Identified Platform as: " <> T.pack (prettyShow pfr)+  pure pfr+ where+  getOpenBSDVersion = lift $ fmap _stdOut $ executeOut "uname" ["-r"] Nothing+  getFreeBSDVersion = lift $ fmap _stdOut $ executeOut "freebsd-version" [] Nothing+  getDarwinVersion = lift $ fmap _stdOut $ executeOut "sw_vers"+                                                        ["-productVersion"]+                                                        Nothing+++getLinuxDistro :: (MonadCatch m, MonadIO m, MonadFail m)+               => Excepts '[DistroNotFound] m (LinuxDistro, Maybe Versioning)+getLinuxDistro = do+  -- TODO: don't do alternative on IO, because it hides bugs+  (name, mid, ver) <- join $ liftIO $ handleIO (\_ -> pure (throwE DistroNotFound)) $ fmap pure $ asum+    [ try_os_release+    , try_lsb_release_cmd+    , try_redhat_release+    , try_debian_version+    ]+  let hasWord xs = let f t = any (\x -> match (regex x) (T.unpack t)) xs+                   in f name || maybe False f mid+  let parsedVer = ver >>= either (const Nothing) Just . versioning+      distro    = if+        | hasWord ["debian"]                      -> Debian+        | hasWord ["ubuntu"]                      -> Ubuntu+        | hasWord ["linuxmint", "Linux Mint"]     -> Mint+        | hasWord ["fedora"]                      -> Fedora+        | hasWord ["centos"]                      -> CentOS+        | hasWord ["Red Hat"]                     -> RedHat+        | hasWord ["alpine"]                      -> Alpine+        | hasWord ["exherbo"]                     -> Exherbo+        | hasWord ["gentoo"]                      -> Gentoo+        | hasWord ["opensuse", "suse"]            -> OpenSUSE+        | hasWord ["amazonlinux", "Amazon Linux"] -> AmazonLinux+        | hasWord ["rocky", "Rocky Linux"]        -> Rocky+        -- https://github.com/void-linux/void-packages/blob/master/srcpkgs/base-files/files/os-release+        | hasWord ["void", "Void Linux"]          -> Void+        | otherwise                               -> UnknownLinux+  pure (distro, parsedVer)+ where+  regex x = makeRegexOpts compIgnoreCase execBlank ([s|\<|] ++ x ++ [s|\>|])++  lsb_release_cmd :: FilePath+  lsb_release_cmd = "lsb-release"+  redhat_release :: FilePath+  redhat_release = "/etc/redhat-release"+  debian_version :: FilePath+  debian_version = "/etc/debian_version"++  try_os_release :: IO (Text, Maybe Text, Maybe Text)+  try_os_release = do+    Just OsRelease{ name = name, version_id = version_id, OSR.id = id' } <-+      fmap osRelease <$> parseOsRelease+    pure (T.pack name, Just (T.pack id'), fmap T.pack version_id)++  try_lsb_release_cmd :: (MonadFail m, MonadIO m)+                      => m (Text, Maybe Text, Maybe Text)+  try_lsb_release_cmd = do+    (Just _) <- liftIO $ findExecutable lsb_release_cmd+    name     <- fmap _stdOut $ executeOut lsb_release_cmd ["-si"] Nothing+    ver      <- fmap _stdOut $ executeOut lsb_release_cmd ["-sr"] Nothing+    pure (decUTF8Safe' name, Nothing, Just $ decUTF8Safe' ver)++  try_redhat_release :: IO (Text, Maybe Text, Maybe Text)+  try_redhat_release = do+    t <- T.readFile redhat_release+    let nameRegex n =+          makeRegexOpts compIgnoreCase+                        execBlank+                        ([s|\<|] <> fS n <> [s|\>|] :: ByteString) :: Regex+    let verRegex =+          makeRegexOpts compIgnoreCase+                        execBlank+                        ([s|\<([0-9])+(.([0-9])+)*\>|] :: ByteString) :: Regex+    let nameRe n =+          fromEmpty . match (nameRegex n) $ T.unpack t :: Maybe String+        verRe = fromEmpty . match verRegex $ T.unpack t :: Maybe String+    (Just name) <- pure+      (nameRe "CentOS" <|> nameRe "Fedora" <|> nameRe "Red Hat")+    pure (T.pack name, Nothing, fmap T.pack verRe)+   where+    fromEmpty :: String -> Maybe String+    fromEmpty "" = Nothing+    fromEmpty s' = Just s'++  try_debian_version :: IO (Text, Maybe Text, Maybe Text)+  try_debian_version = do+    ver <- T.readFile debian_version+    pure (T.pack "debian", Just (T.pack "debian"), Just ver)+++getStackGhcBuilds :: (MonadReader env m, HasLog env, MonadIO m)+                  => PlatformResult+                  -> Excepts '[ParseError, NoCompatiblePlatform, DistroNotFound, ProcessError] m [String]+getStackGhcBuilds PlatformResult{..} = do+    case _platform of+      Linux _ -> do+        -- Some systems don't have ldconfig in the PATH, so make sure to look in+        -- /sbin and /usr/sbin as well+        sbinEnv <- liftIO $ addToPath sbinDirs False+        ldConfig <- lift $ executeOut' "ldconfig" ["-p"] Nothing (Just sbinEnv)+        firstWords <- case ldConfig of+                        CapturedProcess ExitSuccess so _ ->+                          pure . mapMaybe (listToMaybe . T.words) . T.lines . T.pack . stripNewlineEnd . T.unpack . decUTF8Safe' $ so+                        CapturedProcess (ExitFailure _) _ _ ->+                          -- throwE $ NonZeroExit c "ldconfig" ["-p" ]+                          pure []+        let checkLib :: (MonadReader env m, HasLog env, MonadIO m) => String -> m Bool+            checkLib lib+              | libT `elem` firstWords = do+                  logDebug $ "Found shared library " <> libT <> " in 'ldconfig -p' output"+                  pure True+              | isWindows =+                  -- Cannot parse /usr/lib on Windows+                  pure False+              | otherwise = hasMatches lib usrLibDirs+              -- This is a workaround for the fact that libtinfo.so.x doesn't+              -- appear in the 'ldconfig -p' output on Arch or Slackware even+              -- when it exists. There doesn't seem to be an easy way to get the+              -- true list of directories to scan for shared libs, but this+              -- works for our particular cases.+             where+              libT = T.pack lib++            hasMatches :: (MonadReader env m, HasLog env, MonadIO m) => String -> [FilePath] -> m Bool+            hasMatches lib dirs = do+              matches <- filterM (liftIO . doesFileExist . (</> lib)) dirs+              case matches of+                [] -> logDebug ("Did not find shared library " <> libT) >> pure False+                (path:_) -> logDebug ("Found shared library " <> libT <> " in " <> T.pack path) >> pure True+             where+              libT = T.pack lib++            getLibc6Version :: MonadIO m+                            => Excepts '[ParseError, ProcessError] m Version+            getLibc6Version = do+              CapturedProcess{..} <- lift $ executeOut "ldd" ["--version"] Nothing+              case _exitCode of+                ExitSuccess -> either (throwE . ParseError . show) pure+                                 . MP.parse lddVersion "" . T.pack . stripNewlineEnd . T.unpack . decUTF8Safe' $ _stdOut+                ExitFailure c -> throwE $ NonZeroExit c "ldd" ["--version" ]++            -- Assumes the first line of ldd has the format:+            --+            -- ldd (...) nn.nn+            --+            -- where nn.nn corresponds to the version of libc6.+            lddVersion :: MP.Parsec Void Text Version+            lddVersion = do+              skipWhile (/= ')')+              skip (== ')')+              skipSpace+              version'++        hasMusl <- hasMatches relFileLibcMuslx86_64So1 libDirs+        mLibc6Version <- veitherToEither <$> runE getLibc6Version+        case mLibc6Version of+          Right libc6Version -> logDebug $ "Found shared library libc6 in version: " <> prettyVer libc6Version+          Left _ -> logDebug "Did not find a version of shared library libc6."+        let hasLibc6_2_32 = either (const False) (>= [vver|2.32|]) mLibc6Version+        hastinfo5 <- checkLib relFileLibtinfoSo5+        hastinfo6 <- checkLib relFileLibtinfoSo6+        hasncurses6 <- checkLib relFileLibncurseswSo6+        hasgmp5 <- checkLib relFileLibgmpSo10+        hasgmp4 <- checkLib relFileLibgmpSo3+        let libComponents = if hasMusl+              then+                [ ["musl"] ]+              else+                concat+                  [ if hastinfo6 && hasgmp5+                    then+                      if hasLibc6_2_32+                      then [["tinfo6"]]+                      else [["tinfo6-libc6-pre232"]]+                    else [[]]+                  , [ [] | hastinfo5 && hasgmp5 ]+                  , [ ["ncurses6"] | hasncurses6 && hasgmp5 ]+                  , [ ["gmp4"] | hasgmp4 ]+                  ]+        pure $ map+          (\c -> case c of+            [] -> []+            _  -> L.intercalate "-" c)+          libComponents+      OpenBSD -> pure []+      FreeBSD ->+        case _distroVersion of+          Just fVer+            | fVer >= [vers|12|] -> pure []+          _ -> pure ["ino64"]+      Darwin  -> pure []+      Windows -> pure []+ where++  relFileLibcMuslx86_64So1 :: FilePath+  relFileLibcMuslx86_64So1 = "libc.musl-x86_64.so.1"+  libDirs :: [FilePath]+  libDirs = ["/lib", "/lib64"]+  usrLibDirs :: [FilePath]+  usrLibDirs = ["/usr/lib", "/usr/lib64"]+  sbinDirs :: [FilePath]+  sbinDirs = ["/sbin", "/usr/sbin"]+  relFileLibtinfoSo5 :: FilePath+  relFileLibtinfoSo5 = "libtinfo.so.5"+  relFileLibtinfoSo6 :: FilePath+  relFileLibtinfoSo6 = "libtinfo.so.6"+  relFileLibncurseswSo6 :: FilePath+  relFileLibncurseswSo6 = "libncursesw.so.6"+  relFileLibgmpSo10 :: FilePath+  relFileLibgmpSo10 = "libgmp.so.10"+  relFileLibgmpSo3 :: FilePath+  relFileLibgmpSo3 = "libgmp.so.3"++getStackOSKey :: Monad m => PlatformRequest -> Excepts '[UnsupportedSetupCombo] m String+getStackOSKey PlatformRequest { .. } =+  case (_rArch, _rPlatform) of+    (A_32   , Linux _) -> pure "linux32"+    (A_64   , Linux _) -> pure "linux64"+    (A_32   , Darwin ) -> pure "macosx"+    (A_64   , Darwin ) -> pure "macosx"+    (A_32   , FreeBSD) -> pure "freebsd32"+    (A_64   , FreeBSD) -> pure "freebsd64"+    (A_32   , OpenBSD) -> pure "openbsd32"+    (A_64   , OpenBSD) -> pure "openbsd64"+    (A_32   , Windows) -> pure "windows32"+    (A_64   , Windows) -> pure "windows64"+    (A_ARM  , Linux _) -> pure "linux-armv7"+    (A_ARM64, Linux _) -> pure "linux-aarch64"+    (A_Sparc, Linux _) -> pure "linux-sparc"+    (A_ARM64, Darwin ) -> pure "macosx-aarch64"+    (A_ARM64, FreeBSD) -> pure "freebsd-aarch64"+    (A_ARM64, OpenBSD) -> pure "openbsd-aarch64"+    (arch', os')       -> throwE $ UnsupportedSetupCombo arch' os'++getStackPlatformKey :: (MonadReader env m, MonadFail m, HasLog env, MonadCatch m, MonadIO m)+                    => PlatformRequest+                    -> Excepts '[UnsupportedSetupCombo, ParseError, NoCompatiblePlatform, NoCompatibleArch, DistroNotFound, ProcessError] m [String]+getStackPlatformKey pfreq@PlatformRequest{..} = do+  osKey <- liftE  $ getStackOSKey pfreq+  builds <- liftE $ getStackGhcBuilds (PlatformResult _rPlatform _rVersion)+  let builds' = (\build -> if null build then osKey else osKey <> "-" <> build) <$> builds+  logDebug $ "Potential GHC builds: " <> mconcat (L.intersperse ", " $ fmap T.pack builds')+  pure builds'+
− lib/GHCup/Requirements.hs
@@ -1,75 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--{-|-Module      : GHCup.Requirements-Description : Requirements utilities-Copyright   : (c) Julian Ospald, 2020-License     : LGPL-3.0-Maintainer  : hasufell@hasufell.de-Stability   : experimental-Portability : portable--}-module GHCup.Requirements where--import           GHCup.Types-import           GHCup.Types.JSON               ( )-import           GHCup.Types.Optics-import           GHCup.Version--import           Control.Applicative-import           Data.List                      ( find )-import           Data.Maybe-import           Optics-import           Prelude                 hiding ( abs-                                                , readFile-                                                , writeFile-                                                )--import qualified Data.Map.Strict               as M-import qualified Data.Text                     as T----- | Get the requirements. Right now this combines GHC and cabal--- and doesn't do fine-grained distinction. However, the 'ToolRequirements'--- type allows it.-getCommonRequirements :: PlatformResult-                      -> ToolRequirements-                      -> Maybe Requirements-getCommonRequirements pr tr =-  with_distro <|> without_distro_ver <|> without_distro- where-  with_distro        = distro_preview _platform _distroVersion-  without_distro_ver = distro_preview _platform (const Nothing)-  without_distro     = distro_preview (set _Linux UnknownLinux . _platform) (const Nothing)--  distro_preview f g =-    let platformVersionSpec =-          preview (ix GHC % ix Nothing % to unMapIgnoreUnknownKeys % ix (f pr)) tr-        mv' = g pr-    in  fmap snd-          .   find-                (\(mverRange, _) -> maybe-                  (isNothing mv')-                  (\range -> maybe False (`versionRange` range) mv')-                  mverRange-                )-          .   M.toList-          =<< platformVersionSpec---prettyRequirements :: Requirements -> T.Text-prettyRequirements Requirements {..} =-  let d = if not . null $ _distroPKGs-        then "\n  Please ensure the following distro packages "-          <> "are installed before continuing (you can exit ghcup "-          <> "and return at any time): "-          <> T.intercalate " " _distroPKGs-        else ""-      n = if not . T.null $ _notes then "\n  Note: " <> _notes else ""-  in  "System requirements " <> d <> n--rawRequirements :: Requirements -> T.Text-rawRequirements Requirements {..} =-  if not . null $ _distroPKGs-  then T.intercalate " " _distroPKGs-  else ""
+ lib/GHCup/Setup.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}++module GHCup.Setup where++import GHCup.Download+import GHCup.Errors+import GHCup.Hardcoded.URLs+import GHCup.Prelude+import GHCup.Query.GHCupDirs+import GHCup.Types+import GHCup.Types.Optics++import Control.Monad        ( void )+import Control.Monad.Reader ( MonadReader )+import Control.Monad.Trans  ( lift )+import Data.Variant.Excepts+import System.FilePath      ( (</>) )+import System.IO.Error      ( doesNotExistErrorType )+import URI.ByteString       ( serializeURIRef' )++import qualified Data.Text as T++ensureShimGen :: ( HasLog env+                 , MonadReader env m+                 , HasDirs env+                 , HasSettings env+                 , HasGHCupInfo env+                 , MonadIOish m+                 )+              => Excepts '[URIParseError, GPGError, DigestError, ContentLengthError, DownloadFailed, NoDownload] m ()+ensureShimGen+  | isWindows = do+      dirs <- lift getDirs+      let shimDownload = DownloadInfo { _dlUri = decUTF8Safe . serializeURIRef' $ shimGenURL, _dlSubdir = Nothing, _dlHash = shimGenSHA, _dlCSize = Nothing, _dlOutput = Nothing, _dlTag = Nothing, _dlInstallSpec = Nothing }+      let dl = downloadCached' shimDownload (Just "gs.exe") Nothing+      void $ (\DigestError{} -> do+          lift $ logWarn "Digest doesn't match, redownloading gs.exe..."+          lift $ logDebug ("rm -f " <> T.pack (fromGHCupPath (cacheDir dirs) </> "gs.exe"))+          lift $ hideError doesNotExistErrorType $ recycleFile (fromGHCupPath (cacheDir dirs) </> "gs.exe")+          liftE @'[URIParseError, GPGError, DigestError, ContentLengthError, DownloadFailed] $ dl+        ) `catchE` liftE @'[URIParseError, GPGError, DigestError, ContentLengthError, DownloadFailed] dl+  | otherwise = pure ()+++-- | Ensure ghcup directory structure exists.+ensureDirectories :: Dirs -> IO ()+ensureDirectories (Dirs baseDir binDir cacheDir logsDir confDir trashDir dbDir tmpDir _) = do+  createDirRecursive' (fromGHCupPath baseDir)+  createDirRecursive' (fromGHCupPath baseDir </> "ghc")+  createDirRecursive' (fromGHCupPath baseDir </> "hls")+  createDirRecursive' binDir+  createDirRecursive' (fromGHCupPath cacheDir)+  createDirRecursive' (fromGHCupPath logsDir)+  createDirRecursive' (fromGHCupPath confDir)+  createDirRecursive' (fromGHCupPath trashDir)+  createDirRecursive' (fromGHCupPath dbDir)+  createDirRecursive' (fromGHCupPath tmpDir)+  pure ()
− lib/GHCup/Stack.hs
@@ -1,286 +0,0 @@-{-# LANGUAGE CPP                   #-}-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE FlexibleInstances     #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedStrings     #-}--{-|-Module      : GHCup.Stack-Description : GHCup installation functions for Stack-Copyright   : (c) Julian Ospald, 2020-License     : LGPL-3.0-Maintainer  : hasufell@hasufell.de-Stability   : experimental-Portability : portable--}-module GHCup.Stack where--import           GHCup.Download-import           GHCup.Errors-import           GHCup.Types-import           GHCup.Types.JSON               ( )-import           GHCup.Types.Optics-import           GHCup.Utils-import           GHCup.Prelude-import           GHCup.Prelude.File-import           GHCup.Prelude.Logger--import           Control.Applicative-import           Control.Exception.Safe-import           Control.Monad-#if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )-#endif-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-                                         hiding ( throwM )-import           Data.Either-import           Data.List-import           Data.Ord-import           Data.Maybe-import           Data.Versions                hiding ( patch )-import           Data.Variant.Excepts-import           Optics-import           Prelude                 hiding ( abs-                                                , writeFile-                                                )-import           Safe                    hiding ( at )-import           System.FilePath-import           System.IO.Error--import qualified Data.Text                     as T----    ---------------------    --[ Installation ]---    ------------------------- | Installs stack into @~\/.ghcup\/bin/stack-\<ver\>@ and--- creates a default @stack -> stack-x.y.z.q@ symlink for--- the latest installed version.-installStackBin :: ( MonadMask m-                   , MonadCatch m-                   , MonadReader env m-                   , HasDirs env-                   , HasSettings env-                   , HasPlatformReq env-                   , HasGHCupInfo env-                   , HasLog env-                   , MonadResource m-                   , MonadIO m-                   , MonadUnliftIO m-                   , MonadFail m-                   )-                => Version-                -> InstallDir-                -> Bool            -- ^ Force install-                -> Excepts-                     '[ AlreadyInstalled-                      , CopyError-                      , DigestError-                      , ContentLengthError-                      , GPGError-                      , DownloadFailed-                      , NoDownload-                      , NotInstalled-                      , UnknownArchive-                      , TarDirDoesNotExist-                      , ArchiveResult-                      , FileAlreadyExistsError-                      , URIParseError-                      ]-                     m-                     ()-installStackBin ver installDir forceInstall = do-  dlinfo <- liftE $ getDownloadInfo Stack ver-  installStackBindist dlinfo ver installDir forceInstall----- | Like 'installStackBin', except takes the 'DownloadInfo' as--- argument instead of looking it up from 'GHCupDownloads'.-installStackBindist :: ( MonadMask m-                       , MonadCatch m-                       , MonadReader env m-                       , HasPlatformReq env-                       , HasDirs env-                       , HasSettings env-                       , HasLog env-                       , MonadResource m-                       , MonadIO m-                       , MonadUnliftIO m-                       , MonadFail m-                       )-                    => DownloadInfo-                    -> Version-                    -> InstallDir-                    -> Bool           -- ^ Force install-                    -> Excepts-                         '[ AlreadyInstalled-                          , CopyError-                          , DigestError-                          , ContentLengthError-                          , GPGError-                          , DownloadFailed-                          , NoDownload-                          , NotInstalled-                          , UnknownArchive-                          , TarDirDoesNotExist-                          , ArchiveResult-                          , FileAlreadyExistsError-                          , URIParseError-                          ]-                         m-                         ()-installStackBindist dlinfo ver installDir forceInstall = do-  lift $ logDebug $ "Requested to install stack version " <> prettyVer ver--  PlatformRequest {..} <- lift getPlatformReq-  Dirs {..} <- lift getDirs--  regularStackInstalled <- lift $ stackInstalled ver--  if-    | not forceInstall-    , regularStackInstalled-    , GHCupInternal <- installDir -> do-        throwE $ AlreadyInstalled Stack ver--    | forceInstall-    , regularStackInstalled-    , GHCupInternal <- installDir -> do-        lift $ logInfo "Removing the currently installed version of Stack first!"-        liftE $ rmStackVer ver--    | otherwise -> pure ()--  -- download (or use cached version)-  dl <- liftE $ downloadCached dlinfo Nothing--  -- unpack-  tmpUnpack <- lift withGHCupTmpDir-  liftE $ cleanUpOnError tmpUnpack (unpackToDir (fromGHCupPath tmpUnpack) dl)-  liftE $ catchWarn $ lEM @_ @'[ProcessError] $ darwinNotarization _rPlatform (fromGHCupPath tmpUnpack)--  -- the subdir of the archive where we do the work-  workdir <- maybe (pure tmpUnpack) (liftE . intoSubdir tmpUnpack) (view dlSubdir dlinfo)--  case installDir of-    IsolateDir isoDir -> do                 -- isolated install-      lift $ logInfo $ "isolated installing Stack to " <> T.pack isoDir-      liftE $ installStackUnpacked workdir (IsolateDirResolved isoDir) ver forceInstall-    GHCupInternal -> do                     -- regular install-      liftE $ installStackUnpacked workdir (GHCupBinDir binDir) ver forceInstall----- | Install an unpacked stack distribution.-installStackUnpacked :: (MonadReader env m, HasLog env, MonadCatch m, MonadIO m)-              => GHCupPath      -- ^ Path to the unpacked stack bindist (where the executable resides)-              -> InstallDirResolved-              -> Version-              -> Bool          -- ^ Force install-              -> Excepts '[CopyError, FileAlreadyExistsError] m ()-installStackUnpacked path installDir ver forceInstall = do-  lift $ logInfo "Installing stack"-  let stackFile = "stack"-  liftIO $ createDirRecursive' (fromInstallDir installDir)-  let destFileName = stackFile-                     <> (case installDir of-                          IsolateDirResolved _ -> ""-                          _ -> ("-" <>) .  T.unpack . prettyVer $ ver-                        )-                     <> exeExt-      destPath = fromInstallDir installDir </> destFileName--  copyFileE-    (fromGHCupPath path </> stackFile <> exeExt)-    destPath-    (not forceInstall)-  lift $ chmod_755 destPath----    ------------------    --[ Set stack ]---    ---------------------- | Set the @~\/.ghcup\/bin\/stack@ symlink.-setStack :: ( MonadMask m-            , MonadReader env m-            , HasDirs env-            , HasLog env-            , MonadThrow m-            , MonadFail m-            , MonadIO m-            , MonadUnliftIO m-            )-         => Version-         -> Excepts '[NotInstalled] m ()-setStack ver = do-  let targetFile = "stack-" <> T.unpack (prettyVer ver) <> exeExt--  -- symlink destination-  Dirs {..} <- lift getDirs--  whenM (liftIO $ not <$> doesFileExist (binDir </> targetFile))-    $ throwE-    $ NotInstalled Stack (GHCTargetVersion Nothing ver)--  let stackbin = binDir </> "stack" <> exeExt--  lift $ createLink targetFile stackbin--  liftIO (isShadowed stackbin) >>= \case-    Nothing -> pure ()-    Just pa -> lift $ logWarn $ T.pack $ prettyHFError (ToolShadowed Stack pa stackbin ver)--  pure ()---unsetStack :: ( MonadMask m-              , MonadReader env m-              , HasDirs env-              , MonadIO m)-           => m ()-unsetStack = do-  Dirs {..} <- getDirs-  let stackbin = binDir </> "stack" <> exeExt-  hideError doesNotExistErrorType $ rmLink stackbin---    -----------------    --[ Rm stack ]---    -------------------- | Delete a stack version. Will try to fix the @stack@ symlink--- after removal (e.g. setting it to an older version).-rmStackVer :: ( MonadMask m-              , MonadReader env m-              , HasDirs env-              , MonadThrow m-              , HasLog env-              , MonadIO m-              , MonadFail m-              , MonadCatch m-              , MonadUnliftIO m-              )-           => Version-           -> Excepts '[NotInstalled] m ()-rmStackVer ver = do-  whenM (lift $ fmap not $ stackInstalled ver) $ throwE (NotInstalled Stack (GHCTargetVersion Nothing ver))--  sSet      <- lift stackSet--  Dirs {..} <- lift getDirs--  let stackFile = "stack-" <> T.unpack (prettyVer ver) <> exeExt-  lift $ hideError doesNotExistErrorType $ recycleFile (binDir </> stackFile)--  when (Just ver == sSet) $ do-    sVers <- lift $ fmap rights getInstalledStacks-    case headMay . sortBy (comparing Down) $ sVers of-      Just latestver -> setStack latestver-      Nothing        -> lift $ rmLink (binDir </> "stack" <> exeExt)
+ lib/GHCup/System/Cmd.hs view
@@ -0,0 +1,176 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}++module GHCup.System.Cmd where++import GHCup.Download+import GHCup.Errors+import GHCup.Prelude+import GHCup.Prelude.Process+import GHCup.Prelude.String.QQ+import GHCup.Query.GHCupDirs+import GHCup.Types+import GHCup.Types.Optics++import Control.Exception.Safe+import Control.Monad+import Control.Monad.Reader+import Control.Monad.Trans.Resource ( MonadResource )+import Data.ByteString              ( ByteString )+import Data.Char                    ( isHexDigit )+import Data.List                    ( isPrefixOf, sort, stripPrefix )+import Data.Maybe                   ( catMaybes, isJust )+import Data.Variant.Excepts+import GHC.IO.Exception             ( ExitCode (ExitFailure, ExitSuccess) )+import Safe                         ( atMay )+import System.FilePath              ( getSearchPath, (</>) )+import System.IO.Error              ( isDoesNotExistError, isPermissionError )+import Text.Regex.Posix+    ( RegexMaker (makeRegexOpts), compExtended, execBlank )+import URI.ByteString               ( URI )++import qualified Data.Text as T+++-- | Calls gmake if it exists in PATH, otherwise make.+make :: ( MonadIOish m+        , MonadReader env m+        , HasDirs env+        , HasLog env+        , HasSettings env+        )+     => [String]+     -> Maybe FilePath+     -> m (Either ProcessError ())+make args workdir = make' args workdir "ghc-make" Nothing+++-- | Calls gmake if it exists in PATH, otherwise make.+make' :: ( MonadThrow m+         , MonadIO m+         , MonadReader env m+         , HasDirs env+         , HasLog env+         , HasSettings env+         )+      => [String]+      -> Maybe FilePath+      -> FilePath         -- ^ log filename (opened in append mode)+      -> Maybe [(String, String)] -- ^ optional environment+      -> m (Either ProcessError ())+make' args workdir logfile menv = do+  mymake <- liftIO getBestMake+  execLogged mymake args workdir logfile menv++getBestMake :: IO FilePath+getBestMake = do+  spaths    <- liftIO getSearchPath+  has_gmake <- isJust <$> liftIO (searchPath spaths "gmake")+  let mymake = if has_gmake then "gmake" else "make"+  pure mymake+++makeOut :: (MonadReader env m, HasDirs env, MonadIO m)+        => [String]+        -> Maybe FilePath+        -> m CapturedProcess+makeOut args workdir = do+  spaths    <- liftIO getSearchPath+  has_gmake <- isJust <$> liftIO (searchPath spaths "gmake")+  let mymake = if has_gmake then "gmake" else "make"+  executeOut mymake args workdir+++-- | Try to apply patches in order. The order is determined by+-- a quilt series file (in the patch directory) if one exists,+-- else the patches are applied in lexicographical order.+-- Fails with 'PatchFailed' on first failure.+applyPatches :: (MonadReader env m, HasDirs env, HasLog env, MonadIO m)+             => FilePath   -- ^ dir containing patches+             -> FilePath   -- ^ dir to apply patches in+             -> Excepts '[PatchFailed] m ()+applyPatches pdir ddir = do+  let lexicographical = (fmap . fmap) (pdir </>) $ sort <$> findFiles+        pdir+        (makeRegexOpts compExtended+                       execBlank+                       ([s|.+\.(patch|diff)$|] :: ByteString)+        )+  let quilt = map (pdir </>) . lines <$> readFile (pdir </> "series")++  patches <- liftIO $ quilt `catchIO` (\e ->+    if isDoesNotExistError e || isPermissionError e then+      lexicographical+    else throwIO e)+  forM_ patches $ \patch' -> applyPatch patch' ddir+++applyPatch :: (MonadReader env m, HasDirs env, HasLog env, MonadIO m)+           => FilePath   -- ^ Patch+           -> FilePath   -- ^ dir to apply patches in+           -> Excepts '[PatchFailed] m ()+applyPatch patch ddir = do+  lift $ logInfo $ "Applying patch " <> T.pack patch+  fmap (either (const Nothing) Just)+       (exec+         "patch"+         ["-p1", "-s", "-f", "-i", patch]+         (Just ddir)+         Nothing)+    !? PatchFailed+++applyAnyPatch :: ( MonadReader env m+                 , HasDirs env+                 , HasLog env+                 , HasSettings env+                 , MonadResource m+                 , MonadIOish m+                 )+              => Maybe (Either FilePath [URI])+              -> FilePath+              -> Excepts '[PatchFailed, DownloadFailed, DigestError, ContentLengthError, GPGError] m ()+applyAnyPatch Nothing _                   = pure ()+applyAnyPatch (Just (Left pdir)) workdir  = liftE $ applyPatches pdir workdir+applyAnyPatch (Just (Right uris)) workdir = do+  tmpUnpack <- fromGHCupPath <$> lift withGHCupTmpDir+  forM_ uris $ \uri -> do+    patch <- liftE $ download uri Nothing Nothing Nothing tmpUnpack Nothing False+    liftE $ applyPatch patch workdir+++-- | https://gitlab.haskell.org/ghc/ghc/-/issues/17353+darwinNotarization :: (MonadReader env m, HasDirs env, MonadIO m)+                   => Platform+                   -> FilePath+                   -> m (Either ProcessError ())+darwinNotarization Darwin path = exec+  "/usr/bin/xattr"+  ["-r", "-d", "com.apple.quarantine", path]+  Nothing+  Nothing+darwinNotarization _ _ = pure $ Right ()++gitOut :: (MonadReader env m, HasLog env, MonadIO m) => [String] -> FilePath -> Excepts '[ProcessError] m T.Text+gitOut args dir = do+  CapturedProcess {..} <- lift $ executeOut "git" args (Just dir)+  case _exitCode of+    ExitSuccess   -> pure $ T.pack $ stripNewlineEnd $ T.unpack $ decUTF8Safe' _stdOut+    ExitFailure c -> do+      let pe = NonZeroExit c "git" args+      lift $ logDebug $ T.pack (prettyHFError pe)+      throwE pe++processBranches :: T.Text -> [String]+processBranches str' = let lines'   = lines (T.unpack str')+                           words'   = fmap words lines'+                           refs     = catMaybes $ fmap (`atMay` 1) words'+                           branches = catMaybes $ fmap (stripPrefix "refs/heads/") $ filter (isPrefixOf "refs/heads/") refs+                       in branches++isCommitHash :: String -> Bool+isCommitHash str' = let hex = all isHexDigit str'+                        len = length str'+                    in hex && len == 40
+ lib/GHCup/System/Directory.hs view
@@ -0,0 +1,70 @@+module GHCup.System.Directory (++  -- System.Directory re-exports+    createDirectory+  , createDirectoryIfMissing+  , renameDirectory+  , listDirectory+  , getDirectoryContents+  , getCurrentDirectory+  , setCurrentDirectory+  , withCurrentDirectory+  , getHomeDirectory+  , XdgDirectory(..)+  , getXdgDirectory+  , XdgDirectoryList(..)+  , getXdgDirectoryList+  , getAppUserDataDirectory+  , getUserDocumentsDirectory+  , getTemporaryDirectory+  , removeFile+  , renameFile+  , renamePath+  , getFileSize+  , canonicalizePath+  , makeAbsolute+  , makeRelativeToCurrentDirectory+  , doesPathExist+  , doesFileExist+  , doesDirectoryExist+  , findExecutable+  , findExecutables+  , findExecutablesInDirectories+  , findFile+  , findFileWith+  , findFilesWith+  , exeExtension+  , createFileLink+  , createDirectoryLink+  , removeDirectoryLink+  , pathIsSymbolicLink+  , getSymbolicLinkTarget+  , Permissions+  , emptyPermissions+  , readable+  , writable+  , executable+  , searchable+  , setOwnerReadable+  , setOwnerWritable+  , setOwnerExecutable+  , setOwnerSearchable+  , getPermissions+  , setPermissions+  , copyPermissions+  , getAccessTime+  , getModificationTime+  , setAccessTime+  , setModificationTime+  , isSymbolicLink+  )+  where++import GHCup.Prelude.File.Search+import System.Directory          hiding+    ( findFiles+    , makeAbsolute+    , removeDirectory+    , removeDirectoryRecursive+    , removePathForcibly+    )
lib/GHCup/Types.hs view
@@ -1,861 +1,1419 @@ {-# OPTIONS_GHC -Wno-orphans #-}-{-# LANGUAGE CPP               #-}-{-# LANGUAGE BangPatterns      #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE DeriveGeneric     #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE DuplicateRecordFields #-}--{-|-Module      : GHCup.Types-Description : GHCup types-Copyright   : (c) Julian Ospald, 2020-License     : LGPL-3.0-Maintainer  : hasufell@hasufell.de-Stability   : experimental-Portability : portable--}-module GHCup.Types-  ( module GHCup.Types-#if defined(BRICK)-  , Key(..)-  , Modifier(..)-#endif-  , ArchiveResult(..)-  )-  where--import           GHCup.Types.Stack              ( SetupInfo )-import           GHCup.Utils.Tar.Types          ( ArchiveResult(..) )-import {-# SOURCE #-} GHCup.Utils.Dirs          ( fromGHCupPath, GHCupPath )--import           Control.DeepSeq                ( NFData, rnf )-import           Data.Map.Strict                ( Map )-import           Data.List.NonEmpty             ( NonEmpty (..) )-import           Data.Time.Calendar             ( Day )-import           Data.Text                      ( Text )-import           Data.Versions-import           GHC.IO.Exception               ( ExitCode )-import           Text.PrettyPrint.HughesPJClass (Pretty, pPrint, text)-import           URI.ByteString-#if defined(BRICK)-import           Graphics.Vty                   ( Key(..), Modifier(..) )-#endif--import qualified Data.ByteString.Lazy          as BL-import qualified Data.Text                     as T-import qualified GHC.Generics                  as GHC-import qualified Data.List.NonEmpty            as NE--#if !defined(BRICK)-data Key = KEsc  | KChar Char | KBS | KEnter-         | KLeft | KRight | KUp | KDown-         | KUpLeft | KUpRight | KDownLeft | KDownRight | KCenter-         | KFun Int | KBackTab | KPrtScr | KPause | KIns-         | KHome | KPageUp | KDel | KEnd | KPageDown | KBegin | KMenu-    deriving (Eq,Show,Read,Ord,GHC.Generic)--data Modifier = MShift | MCtrl | MMeta | MAlt-    deriving (Eq,Show,Read,Ord,GHC.Generic)-#endif--data KeyCombination = KeyCombination { key :: Key, mods :: [Modifier] }-    deriving (Eq,Show,Read,Ord,GHC.Generic)----    ---------------------    --[ GHCInfo Tree ]---    -----------------------data GHCupInfo = GHCupInfo-  { _toolRequirements :: ToolRequirements-  , _ghcupDownloads   :: GHCupDownloads-  , _metadataUpdate   :: Maybe URI-  }-  deriving (Show, GHC.Generic, Eq)--instance NFData GHCupInfo----    --------------------------    --[ Requirements Tree ]---    ----------------------------type ToolRequirements = Map Tool ToolReqVersionSpec-type ToolReqVersionSpec = Map (Maybe Version) PlatformReqSpec-type PlatformReqSpec = MapIgnoreUnknownKeys Platform PlatformReqVersionSpec-type PlatformReqVersionSpec = Map (Maybe VersionRange) Requirements---data Requirements = Requirements-  { _distroPKGs :: [Text]-  , _notes      :: Text-  }-  deriving (Show, GHC.Generic, Eq)--instance NFData Requirements------    ----------------------    --[ Download Tree ]---    -------------------------- | Description of all binary and source downloads. This is a tree--- of nested maps.-type GHCupDownloads = Map Tool ToolVersionSpec-type ToolVersionSpec = Map GHCTargetVersion VersionInfo-type ArchitectureSpec = MapIgnoreUnknownKeys Architecture PlatformSpec-type PlatformSpec = MapIgnoreUnknownKeys Platform PlatformVersionSpec-type PlatformVersionSpec = Map (Maybe VersionRange) DownloadInfo----- | An installable tool.-data Tool = GHC-          | Cabal-          | GHCup-          | HLS-          | Stack-  deriving (Eq, GHC.Generic, Ord, Show, Enum, Bounded)--instance Pretty Tool where-  pPrint GHC = text "ghc"-  pPrint Cabal = text "cabal"-  pPrint GHCup = text "ghcup"-  pPrint HLS = text "hls"-  pPrint Stack = text "stack"--instance NFData Tool----- | All necessary information of a tool version, including--- source download and per-architecture downloads.-data VersionInfo = VersionInfo-  { _viTags        :: [Tag]              -- ^ version specific tag-  , _viReleaseDay  :: Maybe Day-  , _viChangeLog   :: Maybe URI-  , _viSourceDL    :: Maybe DownloadInfo -- ^ source tarball-  , _viTestDL      :: Maybe DownloadInfo -- ^ test tarball-  , _viArch        :: ArchitectureSpec   -- ^ descend for binary downloads per arch-  -- informative messages-  , _viPreInstall  :: Maybe Text-  , _viPostInstall :: Maybe Text-  , _viPostRemove  :: Maybe Text-  , _viPreCompile  :: Maybe Text-  }-  deriving (Eq, GHC.Generic, Show)--instance NFData VersionInfo----- | A tag. These are currently attached to a version of a tool.-data Tag = Latest             -- ^ the latest version of a tool (unique per tool)-         | Recommended        -- ^ the recommended version of a tool (unique per tool)-         | Prerelease         -- ^ denotes a prerelease version-                              --   (a version should either be 'Prerelease' or-                              --   'LatestPrerelease', but not both)-         | LatestPrerelease   -- ^ the latest prerelease (unique per tool)-         | Nightly            -- ^ denotes a nightly version-                              --   (a version should either be 'Nightly' or-                              --   'LatestNightly', but not both)-         | LatestNightly      -- ^ the latest nightly (unique per tool)-         | Base PVP           -- ^ the base version shipped with GHC-         | Old                -- ^ old versions are hidden by default in TUI-         | Experimental       -- ^ an experiemntal version/bindist-         | UnknownTag String  -- ^ used for upwardscompat-         deriving (Ord, Eq, GHC.Generic, Show) -- FIXME: manual JSON instance--instance NFData Tag--tagToString :: Tag -> String-tagToString Recommended        = "recommended"-tagToString Latest             = "latest"-tagToString Prerelease         = "prerelease"-tagToString Nightly            = "nightly"-tagToString (Base       pvp'') = "base-" ++ T.unpack (prettyPVP pvp'')-tagToString (UnknownTag t    ) = t-tagToString LatestPrerelease   = "latest-prerelease"-tagToString LatestNightly      = "latest-nightly"-tagToString Experimental       = "experimental"-tagToString Old                = ""--instance Pretty Tag where-  pPrint Recommended        = text "recommended"-  pPrint Latest             = text "latest"-  pPrint Prerelease         = text "prerelease"-  pPrint Nightly            = text "nightly"-  pPrint (Base       pvp'') = text ("base-" ++ T.unpack (prettyPVP pvp''))-  pPrint (UnknownTag t    ) = text t-  pPrint LatestPrerelease   = text "latest-prerelease"-  pPrint LatestNightly      = text "latest-prerelease"-  pPrint Experimental       = text "experimental"-  pPrint Old                = mempty--data Architecture = A_64-                  | A_32-                  | A_PowerPC-                  | A_PowerPC64-                  | A_Sparc-                  | A_Sparc64-                  | A_ARM-                  | A_ARM64-  deriving (Eq, GHC.Generic, Ord, Show, Bounded, Enum)--instance NFData Architecture--archToString :: Architecture -> String-archToString A_64 = "x86_64"-archToString A_32 = "i386"-archToString A_PowerPC = "powerpc"-archToString A_PowerPC64 = "powerpc64"-archToString A_Sparc = "sparc"-archToString A_Sparc64 = "sparc64"-archToString A_ARM = "arm"-archToString A_ARM64 = "aarch64"--instance Pretty Architecture where-  pPrint = text . archToString--data Platform = Linux LinuxDistro-              -- ^ must exit-              | Darwin-              -- ^ must exit-              | FreeBSD-              | OpenBSD-              | Windows-              -- ^ must exit-  deriving (Eq, GHC.Generic, Ord, Show)--instance NFData Platform--platformToString :: Platform -> String-platformToString (Linux distro) = "linux-" ++ distroToString distro-platformToString Darwin = "darwin"-platformToString FreeBSD = "freebsd"-platformToString OpenBSD = "openbsd"-platformToString Windows = "windows"--instance Pretty Platform where-  pPrint = text . platformToString--data LinuxDistro = Debian-                 | Ubuntu-                 | Mint-                 | Fedora-                 | CentOS-                 | RedHat-                 | Alpine-                 | AmazonLinux-                 | Rocky-                 | Void-                 -- rolling-                 | Gentoo-                 | Exherbo-                 | OpenSUSE-                 -- not known-                 | UnknownLinux-  deriving (Bounded, Eq, Enum, GHC.Generic, Ord, Show)--allDistros :: [LinuxDistro]-allDistros = enumFromTo minBound maxBound--instance NFData LinuxDistro--distroToString :: LinuxDistro -> String-distroToString Debian = "debian"-distroToString Ubuntu = "ubuntu"-distroToString Mint = "mint"-distroToString Fedora = "fedora"-distroToString CentOS = "centos"-distroToString RedHat = "redhat"-distroToString Alpine = "alpine"-distroToString AmazonLinux = "amazon"-distroToString Rocky = "rocky"-distroToString Void = "void"-distroToString Gentoo = "gentoo"-distroToString Exherbo = "exherbo"-distroToString OpenSUSE = "opensuse"-distroToString UnknownLinux = "unknown"--instance Pretty LinuxDistro where-  pPrint = text . distroToString----- | An encapsulation of a download. This can be used--- to download, extract and install a tool.-data DownloadInfo = DownloadInfo-  { _dlUri    :: Text-  , _dlSubdir :: Maybe TarDir-  , _dlHash   :: Text-  , _dlCSize  :: Maybe Integer-  , _dlOutput :: Maybe FilePath-  , _dlTag    :: Maybe [Tag]-  }-  deriving (Eq, Ord, GHC.Generic, Show)--instance NFData DownloadInfo----    ---------------    --[ Others ]---    ----------------data DownloadMirror = DownloadMirror {-     authority :: Authority-   , pathPrefix :: Maybe Text-} deriving (Eq, Ord, GHC.Generic, Show)--instance NFData DownloadMirror--newtype DownloadMirrors = DM (Map Text DownloadMirror)-  deriving (Eq, Ord, GHC.Generic, Show)--instance NFData DownloadMirrors--instance NFData UserInfo-instance NFData Host-instance NFData Port-instance NFData Authority----- | How to descend into a tar archive.-data TarDir = RealDir FilePath-            | RegexDir String     -- ^ will be compiled to regex, the first match will "win"-            deriving (Eq, Ord, GHC.Generic, Show)--instance NFData TarDir--instance Pretty TarDir where-  pPrint (RealDir path) = text path-  pPrint (RegexDir regex) = text regex----- | Where to fetch GHCupDownloads from.-data URLSource = GHCupURL-               | StackSetupURL-               | OwnSource     [Either (Either GHCupInfo SetupInfo) URI] -- ^ complete source list-               | OwnSpec               (Either GHCupInfo SetupInfo)-               | AddSource     [Either (Either GHCupInfo SetupInfo) URI] -- ^ merge with GHCupURL-               | SimpleList    [NewURLSource]-               deriving (Eq, GHC.Generic, Show)--data NewURLSource = NewGHCupURL-                  | NewStackSetupURL-                  | NewGHCupInfo     GHCupInfo-                  | NewSetupInfo     SetupInfo-                  | NewURI           URI-                  | NewChannelAlias  ChannelAlias-               deriving (Eq, GHC.Generic, Show)--instance NFData NewURLSource---- | Alias for ease of URLSource selection-data ChannelAlias = DefaultChannel-                  | StackChannel-                  | CrossChannel-                  | PrereleasesChannel-                  | VanillaChannel-                  deriving (Eq, GHC.Generic, Show, Enum, Bounded)--channelAliasText :: ChannelAlias -> Text-channelAliasText DefaultChannel = "default"-channelAliasText StackChannel = "stack"-channelAliasText CrossChannel = "cross"-channelAliasText PrereleasesChannel = "prereleases"-channelAliasText VanillaChannel = "vanilla"--fromURLSource :: URLSource -> [NewURLSource]-fromURLSource GHCupURL              = [NewGHCupURL]-fromURLSource StackSetupURL         = [NewStackSetupURL]-fromURLSource (OwnSource arr)       = convert' <$> arr-fromURLSource (AddSource arr)       = NewGHCupURL:(convert' <$> arr)-fromURLSource (SimpleList arr)      = arr-fromURLSource (OwnSpec (Left gi))   = [NewGHCupInfo gi]-fromURLSource (OwnSpec (Right si)) = [NewSetupInfo si]--convert' :: Either (Either GHCupInfo SetupInfo) URI -> NewURLSource-convert' (Left (Left gi))  = NewGHCupInfo gi-convert' (Left (Right si)) = NewSetupInfo si-convert' (Right uri)       = NewURI uri--instance NFData URLSource-instance NFData ChannelAlias-instance NFData (URIRef Absolute) where-  rnf (URI !_ !_ !_ !_ !_) = ()---data MetaMode = Strict-              | Lax-  deriving (Show, Read, Eq, GHC.Generic)--instance NFData MetaMode--data UserSettings = UserSettings-  { uCache             :: Maybe Bool-  , uMetaCache         :: Maybe Integer-  , uMetaMode          :: Maybe MetaMode-  , uNoVerify          :: Maybe Bool-  , uVerbose           :: Maybe Bool-  , uKeepDirs          :: Maybe KeepDirs-  , uDownloader        :: Maybe Downloader-  , uKeyBindings       :: Maybe UserKeyBindings-  , uUrlSource         :: Maybe URLSource-  , uNoNetwork         :: Maybe Bool-  , uGPGSetting        :: Maybe GPGSetting-  , uPlatformOverride  :: Maybe PlatformRequest-  , uMirrors           :: Maybe DownloadMirrors-  , uDefGHCConfOptions :: Maybe [String]-  , uPager             :: Maybe PagerConfig-  , uGuessVersion      :: Maybe Bool-  }-  deriving (Show, GHC.Generic, Eq)--defaultUserSettings :: UserSettings-defaultUserSettings = UserSettings Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing--fromSettings :: Settings -> Maybe KeyBindings -> UserSettings-fromSettings Settings{..} Nothing =-  UserSettings {-      uCache = Just cache-    , uMetaCache = Just metaCache-    , uMetaMode = Just metaMode-    , uNoVerify = Just noVerify-    , uVerbose = Just verbose-    , uKeepDirs = Just keepDirs-    , uDownloader = Just downloader-    , uNoNetwork = Just noNetwork-    , uKeyBindings = Nothing-    , uUrlSource = Just (SimpleList urlSource)-    , uGPGSetting = Just gpgSetting-    , uPlatformOverride = platformOverride-    , uMirrors = Just mirrors-    , uDefGHCConfOptions = Just defGHCConfOptions-    , uPager = Just pager-    , uGuessVersion = Just guessVersion-  }-fromSettings Settings{..} (Just KeyBindings{..}) =-  let ukb = UserKeyBindings-            { kUp           = Just bUp-            , kDown         = Just bDown-            , kQuit         = Just bQuit-            , kInstall      = Just bInstall-            , kUninstall    = Just bUninstall-            , kSet          = Just bSet-            , kChangelog    = Just bChangelog-            , kShowAll      = Just bShowAllVersions-            }-  in UserSettings {-      uCache = Just cache-    , uMetaCache = Just metaCache-    , uMetaMode = Just metaMode-    , uNoVerify = Just noVerify-    , uVerbose = Just verbose-    , uKeepDirs = Just keepDirs-    , uDownloader = Just downloader-    , uNoNetwork = Just noNetwork-    , uKeyBindings = Just ukb-    , uUrlSource = Just (SimpleList urlSource)-    , uGPGSetting = Just gpgSetting-    , uPlatformOverride = platformOverride-    , uMirrors = Just mirrors-    , uDefGHCConfOptions = Just defGHCConfOptions-    , uPager = Just pager-    , uGuessVersion = Just guessVersion-  }--data UserKeyBindings = UserKeyBindings-  { kUp           :: Maybe KeyCombination-  , kDown         :: Maybe KeyCombination-  , kQuit         :: Maybe KeyCombination-  , kInstall      :: Maybe KeyCombination-  , kUninstall    :: Maybe KeyCombination-  , kSet          :: Maybe KeyCombination-  , kChangelog    :: Maybe KeyCombination-  , kShowAll      :: Maybe KeyCombination-  }-  deriving (Show, GHC.Generic, Eq)--data KeyBindings = KeyBindings-  { bUp              :: KeyCombination-  , bDown            :: KeyCombination-  , bQuit            :: KeyCombination-  , bInstall         :: KeyCombination-  , bUninstall       :: KeyCombination-  , bSet             :: KeyCombination-  , bChangelog       :: KeyCombination-  , bShowAllVersions :: KeyCombination-  }-  deriving (Show, GHC.Generic)--instance NFData KeyBindings-#if !defined(BRICK)-instance NFData Key--instance NFData Modifier--#endif-instance NFData KeyCombination--defaultKeyBindings :: KeyBindings-defaultKeyBindings = KeyBindings-  { bUp              = KeyCombination { key = KUp      , mods = [] }-  , bDown            = KeyCombination { key = KDown    , mods = [] }-  , bQuit            = KeyCombination { key = KChar 'q', mods = [] }-  , bInstall         = KeyCombination { key = KChar 'i', mods = [] }-  , bUninstall       = KeyCombination { key = KChar 'u', mods = [] }-  , bSet             = KeyCombination { key = KChar 's', mods = [] }-  , bChangelog       = KeyCombination { key = KChar 'c', mods = [] }-  , bShowAllVersions = KeyCombination { key = KChar 'a', mods = [] }-  }--data AppState = AppState-  { settings :: Settings-  , dirs :: Dirs-  , keyBindings :: KeyBindings-  , ghcupInfo :: GHCupInfo-  , pfreq :: PlatformRequest-  , loggerConfig :: LoggerConfig-  } deriving (Show, GHC.Generic)--instance NFData AppState--fromAppState :: AppState -> LeanAppState-fromAppState AppState {..} = LeanAppState {..}--data LeanAppState = LeanAppState-  { settings :: Settings-  , dirs :: Dirs-  , keyBindings :: KeyBindings-  , loggerConfig :: LoggerConfig-  } deriving (Show, GHC.Generic)--instance NFData LeanAppState---data Settings = Settings-  { cache             :: Bool-  , metaCache         :: Integer-  , metaMode          :: MetaMode-  , noVerify          :: Bool-  , keepDirs          :: KeepDirs-  , downloader        :: Downloader-  , verbose           :: Bool-  , urlSource         :: [NewURLSource]-  , noNetwork         :: Bool-  , gpgSetting        :: GPGSetting-  , noColor           :: Bool -- this also exists in LoggerConfig-  , platformOverride  :: Maybe PlatformRequest-  , mirrors           :: DownloadMirrors-  , defGHCConfOptions :: [String]-  , pager             :: PagerConfig-  , guessVersion      :: Bool-  }-  deriving (Show, GHC.Generic)--data PagerConfig = PagerConfig {-    pagerList :: Bool-  , pagerCmd  :: Maybe String-  }-  deriving (Show, GHC.Generic, Eq)--instance NFData PagerConfig--defaultPagerConfig :: PagerConfig-defaultPagerConfig = PagerConfig False Nothing--allPagerConfig :: String -> PagerConfig-allPagerConfig cmd = PagerConfig True (Just cmd)--defaultMetaCache :: Integer-defaultMetaCache = 300 -- 5 minutes--defaultSettings :: Settings-defaultSettings = Settings False defaultMetaCache Lax False Never Curl False [NewGHCupURL] False GPGNone False Nothing (DM mempty) [] defaultPagerConfig True--instance NFData Settings--data Dirs = Dirs-  { baseDir    :: GHCupPath-  , binDir     :: FilePath-  , cacheDir   :: GHCupPath-  , logsDir    :: GHCupPath-  , confDir    :: GHCupPath-  , dbDir      :: GHCupPath-  , recycleDir :: GHCupPath -- mainly used on windows-  , tmpDir     :: GHCupPath-  , msys2Dir   :: FilePath-  }-  deriving (Show, GHC.Generic)--instance NFData Dirs--data MSYS2Env = MSYS-              | UCRT64-              | CLANG64-              | CLANGARM64-              | CLANG32-              | MINGW64-              | MINGW32-  deriving (Eq, Show, Ord, GHC.Generic, Read)--instance NFData MSYS2Env--data KeepDirs = Always-              | Errors-              | Never-  deriving (Eq, Show, Ord, GHC.Generic)--instance NFData KeepDirs--data Downloader = Curl-                | Wget-#if defined(INTERNAL_DOWNLOADER)-                | Internal-#endif-  deriving (Eq, Show, Ord, GHC.Generic)--instance NFData Downloader--data GPGSetting = GPGStrict-                | GPGLax-                | GPGNone-  deriving (Eq, Show, Ord, GHC.Generic)--instance NFData GPGSetting--data DebugInfo = DebugInfo-  { diDirs       :: Dirs-  , diArch       :: Architecture-  , diPlatform   :: PlatformResult-  , diChannels   :: [(ChannelAlias, URI)]-  , diShimGenURL :: URI-  }-  deriving Show---data SetGHC = SetGHCOnly  -- ^ unversioned 'ghc'-            | SetGHC_XY   -- ^ ghc-x.y-            | SetGHC_XYZ  -- ^ ghc-x.y.z-            deriving (Eq, Show)--data SetHLS = SetHLSOnly  -- ^ unversioned 'hls'-            | SetHLS_XYZ  -- ^ haskell-language-server-a.b.c~x.y.z, where a.b.c is GHC version and x.y.z is HLS version-            deriving (Eq, Show)---data PlatformResult = PlatformResult-  { _platform      :: Platform-  , _distroVersion :: Maybe Versioning-  }-  deriving (Eq, Show, GHC.Generic)--instance NFData PlatformResult--platResToString :: PlatformResult -> String-platResToString PlatformResult { _platform = plat, _distroVersion = Just v' }-  = show plat <> ", " <> T.unpack (prettyV v')-platResToString PlatformResult { _platform = plat, _distroVersion = Nothing }-  = show plat--instance Pretty PlatformResult where-  pPrint = text . platResToString--data PlatformRequest = PlatformRequest-  { _rArch     :: Architecture-  , _rPlatform :: Platform-  , _rVersion  :: Maybe Versioning-  }-  deriving (Eq, Show, GHC.Generic)--instance NFData PlatformRequest--pfReqToString :: PlatformRequest -> String-pfReqToString (PlatformRequest arch plat ver) =-  archToString arch ++ "-" ++ platformToString plat ++ pver- where-  pver = case ver of-           Just v' -> "-" ++ T.unpack (prettyV v')-           Nothing -> ""--instance Pretty PlatformRequest where-  pPrint = text . pfReqToString---- | A GHC identified by the target platform triple--- and the version.-data GHCTargetVersion = GHCTargetVersion-  { _tvTarget  :: Maybe Text-  , _tvVersion :: Version-  }-  deriving (Ord, Eq, Show, GHC.Generic)--instance NFData GHCTargetVersion--data GitBranch = GitBranch-  { ref  :: String-  , repo :: Maybe String-  }-  deriving (Ord, Eq, Show)--mkTVer :: Version -> GHCTargetVersion-mkTVer = GHCTargetVersion Nothing--tVerToText :: GHCTargetVersion -> Text-tVerToText (GHCTargetVersion (Just t) v') = t <> "-" <> prettyVer v'-tVerToText (GHCTargetVersion Nothing  v') = prettyVer v'---- | Assembles a path of the form: <target-triple>-<version>-instance Pretty GHCTargetVersion where-  pPrint = text . T.unpack . tVerToText----- | A comparator and a version.-data VersionCmp = VR_gt Versioning-                | VR_gteq Versioning-                | VR_lt Versioning-                | VR_lteq Versioning-                | VR_eq Versioning-  deriving (Eq, GHC.Generic, Ord, Show)--instance NFData VersionCmp----- | A version range. Supports && and ||, but not  arbitrary--- combinations. This is a little simplified.-data VersionRange = SimpleRange (NonEmpty VersionCmp) -- And-                  | OrRange (NonEmpty VersionCmp) VersionRange-  deriving (Eq, GHC.Generic, Ord, Show)--instance NFData VersionRange--instance Pretty VersionCmp where-  pPrint (VR_gt v) = text "> " <> pPrint v-  pPrint (VR_gteq v) = text ">= " <> pPrint v-  pPrint (VR_lt v) = text "< " <> pPrint v-  pPrint (VR_lteq v) = text "<= " <> pPrint v-  pPrint (VR_eq v) = text "= " <> pPrint v--instance Pretty VersionRange where-  pPrint (SimpleRange xs) = foldl1 (\x y -> x <> text " && " <> y) $ NE.map pPrint xs-  pPrint (OrRange xs vr) = foldMap pPrint xs <> " || " <> pPrint vr--instance Pretty Versioning where-  pPrint = text . T.unpack . prettyV--instance Pretty Version where-  pPrint = text . T.unpack . prettyVer--instance Show (a -> b) where-  show _ = "<function>"--instance Show (IO ()) where-  show _ = "<io>"---data LogLevel = Warn-              | Info-              | Debug-              | Error-  deriving (Eq, Ord, Show)--data LoggerConfig = LoggerConfig-  { 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 !_ !_ !fancyColors) = rnf (lcPrintDebug, fancyColors)--data ProcessError = NonZeroExit Int FilePath [String]-                  | PTerminated FilePath [String]-                  | PStopped FilePath [String]-                  | NoSuchPid FilePath [String]-                  deriving Show---data CapturedProcess = CapturedProcess-  { _exitCode :: ExitCode-  , _stdOut   :: BL.ByteString-  , _stdErr   :: BL.ByteString-  }-  deriving (Eq, Show)----data InstallDir = IsolateDir FilePath-                | GHCupInternal-  deriving (Eq, Show)--data InstallDirResolved = IsolateDirResolved FilePath-                        | GHCupDir GHCupPath-                        | GHCupBinDir FilePath-  deriving (Eq, Show)--fromInstallDir :: InstallDirResolved -> FilePath-fromInstallDir (IsolateDirResolved fp) = fp-fromInstallDir (GHCupDir fp) = fromGHCupPath fp-fromInstallDir (GHCupBinDir fp) = fp---isSafeDir :: InstallDirResolved -> Bool-isSafeDir (IsolateDirResolved _) = False-isSafeDir (GHCupDir _)           = True-isSafeDir (GHCupBinDir _)        = False--type PromptQuestion = Text--data PromptResponse = PromptYes | PromptNo-  deriving (Show, Eq)--data ToolVersion = GHCVersion GHCTargetVersion-                 | ToolVersion Version-                 | ToolTag Tag-                 | ToolDay Day-                 deriving (Eq, Show)--instance Pretty ToolVersion where-  pPrint (GHCVersion v) = pPrint v-  pPrint (ToolVersion v) = pPrint v-  pPrint (ToolTag t) = pPrint t-  pPrint (ToolDay d) = text (show d)----data BuildSystem = Hadrian-                 | Make-  deriving (Show, Eq)---data VersionPattern = CabalVer-                    | GitHashShort-                    | GitHashLong-                    | GitDescribe-                    | GitBranchName-                    | S String-  deriving (Eq, Show)---- | Map with custom FromJSON instance which ignores unknown keys-newtype MapIgnoreUnknownKeys k v = MapIgnoreUnknownKeys { unMapIgnoreUnknownKeys :: Map k v }-  deriving (Eq, Show, GHC.Generic)--instance (NFData k, NFData v) => NFData (MapIgnoreUnknownKeys k v)---- | Type representing our guessing modes when e.g. "incomplete" PVP version--- is specified, such as @ghcup set ghc 9.12@.-data GuessMode = GStrict            -- ^ don't guess the proper tool version-               | GLax               -- ^ guess by using the metadata-               | GLaxWithInstalled  -- ^ guess by using metadata and installed versions+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+#if defined(DHALL)+{-# LANGUAGE DeriveAnyClass #-}+#endif++{-|+Module      : GHCup.Types+Description : GHCup types+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Types+  ( module GHCup.Types+#if defined(BRICK)+  , Key(..)+  , Modifier(..)+#endif+  , ArchiveResult(..)+  )+  where++import {-# SOURCE #-} GHCup.Query.GHCupDirs ( GHCupPath, fromGHCupPath )+import                GHCup.Types.Stack     ( SetupInfo )+import                GHCup.Types.Tar       ( ArchiveResult (..) )++import Control.DeepSeq              ( NFData, rnf )+import Control.Monad.Catch+import Control.Monad.IO.Class+import Control.Monad.Trans.Resource+#if defined(DHALL)+import Dhall ( FromDhall, ToDhall )+#endif+import Data.List.NonEmpty             ( NonEmpty (..) )+import Data.Map.Strict                ( Map )+import Data.Text                      ( Text )+import Data.Time.Calendar             ( Day )+import Data.Versions+import GHC.IO.Exception               ( ExitCode )+import Text.PrettyPrint.HughesPJClass ( Pretty, pPrint, text )+import URI.ByteString+#if defined(BRICK)+import Graphics.Vty ( Key (..), Modifier (..) )+#endif+import System.FilePattern++import qualified Data.ByteString.Lazy  as BL+import qualified Data.List.NonEmpty    as NE+import qualified Data.Text             as T+import qualified GHC.Generics          as GHC+import           System.FilePath       ( takeFileName, (<.>) )+import qualified System.FilePath.Posix as Posix+++    -------------------------+    --[ Typeclass aliases ]--+    -------------------------++++type MonadIOish m = ( MonadMask m+                    , MonadCatch m+                    , MonadIO m+                    , MonadUnliftIO m+                    , MonadFail m+                    , MonadThrow m+                    )++    --------------------+    --[ Brick compat ]--+    --------------------++#if !defined(BRICK)+data Key+  = KEsc+  | KChar Char+  | KBS+  | KEnter+  | KLeft+  | KRight+  | KUp+  | KDown+  | KUpLeft+  | KUpRight+  | KDownLeft+  | KDownRight+  | KCenter+  | KFun Int+  | KBackTab+  | KPrtScr+  | KPause+  | KIns+  | KHome+  | KPageUp+  | KDel+  | KEnd+  | KPageDown+  | KBegin+  | KMenu+  deriving (Eq, GHC.Generic, Ord, Read, Show)++data Modifier+  = MShift+  | MCtrl+  | MMeta+  | MAlt+  deriving (Eq, GHC.Generic, Ord, Read, Show)+#endif++data KeyCombination = KeyCombination+  { key :: Key+  , mods :: [Modifier]+  }+  deriving (Eq, GHC.Generic, Ord, Read, Show)++++    --------------------+    --[ GHCInfo Tree ]--+    --------------------+++data GHCupInfo = GHCupInfo+  { _toolRequirements :: ToolRequirements+  , _ghcupDownloads :: GHCupDownloads+  , _metadataUpdate :: Maybe URI+  }+  deriving (Eq, GHC.Generic, Show)++instance NFData GHCupInfo++++    -------------------------+    --[ Requirements Tree ]--+    -------------------------+++type ToolRequirements = Map Tool ToolReqVersionSpec+type ToolReqVersionSpec = Map (Maybe Version) PlatformReqSpec+type PlatformReqSpec = MapIgnoreUnknownKeys Platform PlatformReqVersionSpec+type PlatformReqVersionSpec = Map (Maybe VersionRange) Requirements+++data Requirements = Requirements+  { _distroPKGs :: [Text]+  , _notes :: Text+  }+  deriving (Eq, GHC.Generic, Show)++instance NFData Requirements++++++    ---------------------+    --[ Download Tree ]--+    ---------------------+++-- | Description of all binary and source downloads. This is a tree+-- of nested maps.+newtype GHCupDownloads = GHCupDownloads+  { unGHCupDownloads  :: Map Tool ToolInfo }+  deriving (Eq, GHC.Generic, Ord, Show)++newtype ToolVersionSpec = ToolVersionSpec+  { unToolVersionSpec :: Map TargetVersion VersionMetadata }+  deriving (Eq, GHC.Generic, Ord, Show)++newtype RevisionSpec = RevisionSpec+  { unRevisionSpec :: Map Rev VersionInfo }+  deriving (Eq, GHC.Generic, Ord, Show)++-- for compatibility with Dhall format,+-- which uses:+-- >+-- >    revisionSpec:+-- >    - mapKey: 0+-- >      mapValue:+-- >        viArch:+-- >          ...+newtype RevisionSpecDhall = RevisionSpecDhall+  { unRevisionSpecDhall :: [DhallRevision] }+  deriving (Eq, GHC.Generic, Ord, Show)++data DhallRevision = DhallRevision {+    mapKey :: Int+  , mapValue :: VersionInfo+  }+  deriving (Eq, GHC.Generic, Ord, Show)++newtype ArchitectureSpec = ArchitectureSpec+  { unArchitectureSpnec :: MapIgnoreUnknownKeys Architecture PlatformSpec }+  deriving (Eq, GHC.Generic, Ord, Show)++newtype PlatformSpec = PlatformSpec+  { unPlatformSpec :: MapIgnoreUnknownKeys Platform PlatformVersionSpec }+  deriving (Eq, GHC.Generic, Ord, Show)++newtype PlatformVersionSpec = PlatformVersionSpec+  { unPlatformVersionSpec :: Map (Maybe VersionRange) DownloadInfo }+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData GHCupDownloads+instance NFData ToolVersionSpec+instance NFData RevisionSpec+instance NFData ArchitectureSpec+instance NFData PlatformSpec+instance NFData PlatformVersionSpec++data ToolInfo = ToolInfo {+    _toolVersions :: ToolVersionSpec+  , _toolDetails :: Maybe ToolDescription+  }+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData ToolInfo++data ToolDescription = ToolDescription {+    _toolHomepage    :: Maybe URI+  , _toolRepository  :: Maybe URI+  , _toolDescription :: Text+  , _toolAuthor      :: Maybe String+  , _toolMaintainer  :: Maybe String+  , _toolLicense     :: Maybe String+  , _toolContact     :: Maybe String+  }+  deriving (Eq, GHC.Generic, Show, Ord)++instance NFData ToolDescription++-- | An installable tool.+newtype Tool = Tool String+  deriving (Eq, GHC.Generic, Show, Ord+#if defined(DHALL)+           , FromDhall+           , ToDhall+#endif+           )++-- this type is not consistently used... it's mainly to work+-- around quirks in Dhall, so we can have a proper instance on @Map Rev Blah@+newtype Rev = Rev { unRev :: Int }+  deriving (Eq, GHC.Generic, Show, Ord)++instance NFData Rev++toolPriority :: Tool -> Maybe Int+toolPriority (Tool "ghc")   = Just 1+toolPriority (Tool "cabal") = Just 2+toolPriority (Tool "hls")   = Just 3+toolPriority (Tool "stack") = Just 4+toolPriority (Tool "ghcup") = Just 5+toolPriority (Tool _)       = Nothing+++ghc, hls, stack, cabal, ghcup :: Tool+ghc = Tool "ghc"+hls = Tool "hls"+stack = Tool "stack"+cabal = Tool "cabal"+ghcup = Tool "ghcup"++instance Pretty Tool where+  pPrint (Tool t) = text t++instance NFData Tool++data VersionMetadata = VersionMetadata+  { _vmTags :: [Tag]+  , _vmReleaseDay :: Maybe Day+  , _vmChangeLog :: Maybe URI+  , _vmPreInstall :: Maybe Text+  , _vmPostInstall :: Maybe Text+  , _vmPostRemove :: Maybe Text+  , _vmPreCompile :: Maybe Text+  , _vmRevisionSpec :: RevisionSpec+  }+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData VersionMetadata++-- | All necessary information of a tool version, including+-- source download and per-architecture downloads.+data VersionInfo = VersionInfo+  { _viSourceDL :: Maybe DownloadInfo+    -- ^ source tarball+  , _viTestDL :: Maybe DownloadInfo+    -- ^ test tarball+  , _viArch :: ArchitectureSpec+    -- ^ descend for binary downloads per arch+    -- informative messages+  }+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData VersionInfo+++-- | A tag. These are currently attached to a version of a tool.+data Tag+  = Latest -- ^ the latest version of a tool (unique per tool)+  | Recommended -- ^ the recommended version of a tool (unique per tool)+  | Prerelease -- ^ denotes a prerelease version+  --   (a version should either be 'Prerelease' or+  --   'LatestPrerelease', but not both)+  | LatestPrerelease -- ^ the latest prerelease (unique per tool)+  | Nightly -- ^ denotes a nightly version+  --   (a version should either be 'Nightly' or+  --   'LatestNightly', but not both)+  | LatestNightly -- ^ the latest nightly (unique per tool)+  | Base PVP -- ^ the base version shipped with GHC+  | Old -- ^ old versions are hidden by default in TUI+  | Experimental -- ^ an experimental version/bindist+  | UnknownTag String -- ^ used for upwardscompat+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData Tag++tagToString :: Tag -> String+tagToString Recommended        = "recommended"+tagToString Latest             = "latest"+tagToString Prerelease         = "prerelease"+tagToString Nightly            = "nightly"+tagToString (Base       pvp'') = "base-" ++ T.unpack (prettyPVP pvp'')+tagToString (UnknownTag t    ) = t+tagToString LatestPrerelease   = "latest-prerelease"+tagToString LatestNightly      = "latest-nightly"+tagToString Experimental       = "experimental"+tagToString Old                = ""++instance Pretty Tag where+  pPrint Recommended        = text "recommended"+  pPrint Latest             = text "latest"+  pPrint Prerelease         = text "prerelease"+  pPrint Nightly            = text "nightly"+  pPrint (Base       pvp'') = text ("base-" ++ T.unpack (prettyPVP pvp''))+  pPrint (UnknownTag t    ) = text t+  pPrint LatestPrerelease   = text "latest-prerelease"+  pPrint LatestNightly      = text "latest-prerelease"+  pPrint Experimental       = text "experimental"+  pPrint Old                = mempty++data Architecture+  = A_64+  | A_32+  | A_PowerPC+  | A_PowerPC64+  | A_Sparc+  | A_Sparc64+  | A_ARM+  | A_ARM64+  deriving (Bounded, Enum, Eq, GHC.Generic, Ord, Show)++instance NFData Architecture++archToString :: Architecture -> String+archToString A_64        = "x86_64"+archToString A_32        = "i386"+archToString A_PowerPC   = "powerpc"+archToString A_PowerPC64 = "powerpc64"+archToString A_Sparc     = "sparc"+archToString A_Sparc64   = "sparc64"+archToString A_ARM       = "arm"+archToString A_ARM64     = "aarch64"++instance Pretty Architecture where+  pPrint = text . archToString++data Platform+  = Linux LinuxDistro+  -- ^ must exit+  | Darwin+  -- ^ must exit+  | FreeBSD+  | OpenBSD+  | Windows+  -- ^ must exit+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData Platform++platformToString :: Platform -> String+platformToString (Linux distro) = "linux-" ++ distroToString distro+platformToString Darwin         = "darwin"+platformToString FreeBSD        = "freebsd"+platformToString OpenBSD        = "openbsd"+platformToString Windows        = "windows"++instance Pretty Platform where+  pPrint = text . platformToString++data LinuxDistro = Debian+                 | Ubuntu+                 | Mint+                 | Fedora+                 | CentOS+                 | RedHat+                 | Alpine+                 | AmazonLinux+                 | Rocky+                 | Void+                 -- rolling+                 | Gentoo+                 | Exherbo+                 | OpenSUSE+                 -- not known+                 | UnknownLinux+  deriving (Bounded, Eq, Enum, GHC.Generic, Ord, Show+#if defined(DHALL)+           , FromDhall+           , ToDhall+#endif+           )++allDistros :: [LinuxDistro]+allDistros = enumFromTo minBound maxBound++instance NFData LinuxDistro++distroToString :: LinuxDistro -> String+distroToString Debian       = "debian"+distroToString Ubuntu       = "ubuntu"+distroToString Mint         = "mint"+distroToString Fedora       = "fedora"+distroToString CentOS       = "centos"+distroToString RedHat       = "redhat"+distroToString Alpine       = "alpine"+distroToString AmazonLinux  = "amazon"+distroToString Rocky        = "rocky"+distroToString Void         = "void"+distroToString Gentoo       = "gentoo"+distroToString Exherbo      = "exherbo"+distroToString OpenSUSE     = "opensuse"+distroToString UnknownLinux = "unknown"++instance Pretty LinuxDistro where+  pPrint = text . distroToString+++-- TODO: rename+-- | An encapsulation of a download. This can be used+-- to download, extract and install a tool.+data DownloadInfo = DownloadInfo+  { _dlUri :: Text+  , _dlSubdir :: Maybe TarDir+  , _dlHash :: Text+  , _dlCSize :: Maybe Integer+  , _dlOutput :: Maybe FilePath+  , _dlTag :: Maybe [Tag]+  , _dlInstallSpec :: Maybe InstallationSpecInput+  }+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData DownloadInfo++data InstallMetadata = InstallMetadata {+    _imDownloadInfo :: DownloadInfo+  , _imResolvedInstallSpec :: InstallationSpecResolved+  , _imToolDescription :: Maybe ToolDescription+  , _imRevision :: Int+  }+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData InstallMetadata++defaultGHCExeSymLinked :: PlatformRequest -> TargetVersion -> [String] -> [SymlinkSpec String]+defaultGHCExeSymLinked pfreq tver binaries =+  (\b -> SymlinkSpec (b <.> exeExt)+                     (takeFileName b <> "-${PKGVER}" <.> exeExt)+                     True+                     (Just $ takeFileName b <.> exeExt)+  ) . (\b -> "bin" Posix.</> maybe "" (\t -> T.unpack t <> "-") (_tvTarget tver) <> b) <$> binaries+ where+  exeExt+    | _rPlatform pfreq == Windows = ".exe"+    | otherwise = ""+++defaultGHCInstallSpec :: PlatformRequest -> TargetVersion -> InstallationSpecResolved+defaultGHCInstallSpec pfreq@(PlatformRequest { _rPlatform = Windows }) tver =+  InstallationSpec {+    _isExeRules = [InstallFilePatternRule ["bin/**"]]+  , _isDataRules = [InstallFilePatternRule ["doc/**", "lib/**", "man/**", "mingw/**"]]+  , _isConfigure = Nothing+  , _isMake = Nothing+  , _isExeSymLinked = defaultGHCExeSymLinked pfreq tver (ghcBinaries pfreq tver)+  , _isPreserveMtimes = True+  }+defaultGHCInstallSpec pfreq tver =+  InstallationSpec {+    _isExeRules = []+  , _isDataRules = []+  , _isConfigure = Just ConfigSpec {+      _csConfigArgs = ["--prefix=${PREFIX}"]+    , _csConfigEnv  = Nothing+    , _csConfigFile = Just "configure"+    }+  , _isMake = Just MakeSpec {+      _msMakeArgs   = ["DESTDIR=${TMPDIR}", "install"]+    , _msMakeEnv    = Nothing+    }+  , _isPreserveMtimes = True+  , _isExeSymLinked = defaultGHCExeSymLinked pfreq tver (ghcBinaries pfreq tver)+  }++ghcBinaries :: PlatformRequest -> TargetVersion -> [FilePath]+ghcBinaries _pfreq _tver = ["ghc", "haddock", "hpc", "hsc2hs", "ghci", "ghc-pkg", "hp2ps", "runhaskell", "runghc"]++defaultCabalInstallSpec :: PlatformRequest -> TargetVersion -> InstallationSpecResolved+defaultCabalInstallSpec pfreq _tver = InstallationSpec+  { _isExeRules = [InstallFileRule ("cabal" <.> exeExt) Nothing]+  , _isDataRules = []+  , _isExeSymLinked =+    [SymlinkSpec {+      _slTarget = "cabal" <.> exeExt+    , _slLinkName = "cabal-${PKGVER}" <.> exeExt+    , _slPVPMajorLinks = False+    , _slSetName = Just $ "cabal" <.> exeExt+    }]+  , _isConfigure = Nothing+  , _isMake = Nothing+  , _isPreserveMtimes = False+  }+ where+  exeExt+    | _rPlatform pfreq == Windows = ".exe"+    | otherwise = ""++defaultHLSInstallSpec :: PlatformRequest -> TargetVersion -> InstallationSpecResolved+defaultHLSInstallSpec _pfreq _tver =+  InstallationSpec {+    _isExeRules = []+  , _isDataRules = []+  , _isConfigure = Nothing+  , _isMake = Just MakeSpec {+      _msMakeArgs   = ["DESTDIR=${TMPDIR}", "PREFIX=${PREFIX}", "install"]+    , _msMakeEnv    = Nothing+    }+  , _isPreserveMtimes = False+  , _isExeSymLinked = [] -- we can't figure it out+  }++defaultStackInstallSpec :: PlatformRequest -> TargetVersion -> InstallationSpecResolved+defaultStackInstallSpec pfreq _tver = InstallationSpec+  { _isExeRules = [InstallFileRule ("stack" <.> exeExt) Nothing]+  , _isDataRules = []+  , _isExeSymLinked =+    [SymlinkSpec {+      _slTarget = "stack" <.> exeExt+    , _slLinkName = "stack-${PKGVER}" <.> exeExt+    , _slPVPMajorLinks = False+    , _slSetName = Just $ "stack" <.> exeExt+    }]+  , _isConfigure = Nothing+  , _isMake = Nothing+  , _isPreserveMtimes = False+  }+ where+  exeExt+    | _rPlatform pfreq == Windows = ".exe"+    | otherwise = ""++emptyInstallSpec :: InstallationSpecResolved+emptyInstallSpec = InstallationSpec {+    _isExeRules = []+  , _isDataRules = []+  , _isExeSymLinked = []+  , _isConfigure = Nothing+  , _isMake = Nothing+  , _isPreserveMtimes = False+  }++defaultToolInstallSpec :: Tool -> PlatformRequest -> TargetVersion -> Maybe InstallationSpecResolved+defaultToolInstallSpec (Tool "ghc") pfreq tver = Just $ defaultGHCInstallSpec pfreq tver+defaultToolInstallSpec (Tool "stack") pfreq tver = Just $ defaultStackInstallSpec pfreq tver+defaultToolInstallSpec (Tool "cabal") pfreq tver = Just $ defaultCabalInstallSpec pfreq tver+defaultToolInstallSpec (Tool "hls") pfreq tver = Just $ defaultHLSInstallSpec pfreq tver+defaultToolInstallSpec _ _ _ = Nothing++-- | How to union two environments. Either+-- we prefer the system environment in case+-- of duplicate keys or the spec.+data EnvUnion = PreferSystem+              | PreferSpec+              | OnlySpec+  deriving (Eq, Ord, GHC.Generic, Show+#if defined(DHALL)+           , FromDhall+           , ToDhall+#endif+           )++instance NFData EnvUnion++data EnvSpec = EnvSpec+  { _esEnv :: [(String, String)]+  , _esUnion :: EnvUnion+  }+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData EnvSpec++data ConfigSpec = ConfigSpec+  { _csConfigFile :: Maybe FilePath+  , _csConfigEnv :: Maybe EnvSpec+  , _csConfigArgs :: [String]+  }+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData ConfigSpec++data MakeSpec = MakeSpec+  { _msMakeEnv :: Maybe EnvSpec+  , _msMakeArgs :: [String]+  }+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData MakeSpec++-- | A specification of how to install the tool.+data InstallationSpecGen a = InstallationSpec+  { _isExeRules :: [InstallFileRule]+    -- ^ binaries to install+  , _isDataRules :: [InstallFileRule]+    -- ^ data files to install+  , _isExeSymLinked :: [a]+    -- ^ which binaries to symlink into ~/.ghcup/bin+  , _isConfigure :: Maybe ConfigSpec+  , _isMake :: Maybe MakeSpec+  , _isPreserveMtimes :: Bool+  }+  deriving (Eq, GHC.Generic, Ord, Show)++type InstallationSpecInput = InstallationSpecGen SymlinkInputSpec+type InstallationSpecResolved = InstallationSpecGen SymlinkFileSpec++resolveInstallationSpec :: [SymlinkFileSpec] -> InstallationSpecInput -> InstallationSpecResolved+resolveInstallationSpec symls InstallationSpec{..} =+  InstallationSpec{ _isExeSymLinked = symls, .. }++toInstallationInputSpec :: InstallationSpecResolved -> InstallationSpecInput+toInstallationInputSpec InstallationSpec{..} =+  InstallationSpec { _isExeSymLinked = toInputSpec <$> _isExeSymLinked, .. }++instance NFData a => NFData (InstallationSpecGen a)++data InstallFileRule+  = InstallFileRule+  { _ibrInstallSource :: FilePath+    -- ^ binary to install+  , _ibrInstallDest :: Maybe FilePath+    -- ^ install destination name (must not contain path separators)+  }+  | InstallFilePatternRule+  { _ibrInstallPattern :: [FilePattern]+  }+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData InstallFileRule++data SymlinkSpec a = SymlinkSpec+  { _slTarget :: a+    -- ^ where the symlink will point to+  , _slLinkName :: a+    -- ^ this is the symlink file we will create in @~/.ghcup/bin@+  , _slPVPMajorLinks :: Bool+    -- ^ also create @<tool>-x.y@ on installation+  , _slSetName :: Maybe a+    -- ^ what is the binary name if we "set" the tool+    --   if 'Nothing', then this binary will not be available unqualified+  }+  deriving (Eq, GHC.Generic, Ord, Show)++type SymlinkFileSpec = SymlinkSpec FilePath++instance NFData SymlinkFileSpec++toInputSpec :: SymlinkFileSpec -> SymlinkInputSpec+toInputSpec SymlinkSpec{..} = SymlinkInputSpec{..}++-- | Will be resolced to 'SymlinkSpec'.+data SymlinkInputSpec = SymlinkInputSpec+  { _slTarget :: FilePath+    -- ^ where the symlink will point to (this file exists already)+  , _slLinkName :: FilePath+    -- ^ this is the symlink file we will create in @~/.ghcup/bin@+  , _slPVPMajorLinks :: Bool+    -- ^ also create @<tool>-x.y@ on installation+  , _slSetName :: Maybe FilePath+    -- ^ what is the binary name if we "set" the tool+    --   if 'Nothing', then this binary will not be available unqualified+  } | SymlinkPatternSpec+  { _slTargetPattern :: [FilePattern]+    -- ^ where the symlink will point to (these files exist already)+  , _slTargetPatternIgnore :: [FilePattern]+  , _slLinkName :: FilePath+    -- ^ this is the symlink file we will create in @~/.ghcup/bin@+  , _slPVPMajorLinks :: Bool+    -- ^ also create @<tool>-x.y@ on installation+  , _slSetName :: Maybe FilePath+    -- ^ what is the binary name if we "set" the tool+    --   if 'Nothing', then this binary will not be available unqualified+  }+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData SymlinkInputSpec++++    --------------+    --[ Others ]--+    --------------++data DownloadMirror = DownloadMirror+  { authority :: Authority+  , pathPrefix :: Maybe Text+  }+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData DownloadMirror++newtype DownloadMirrors+  = DM (Map Text DownloadMirror)+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData DownloadMirrors++instance NFData UserInfo+instance NFData Host+instance NFData Port+instance NFData Authority+++-- | How to descend into a tar archive.+data TarDir = RealDir { realDir :: FilePath }+            | RegexDir { regexDir :: String }     -- ^ will be compiled to regex, the first match will "win"+            deriving (Eq, Ord, GHC.Generic, Show+#if defined(DHALL)+           , FromDhall+           , ToDhall+#endif+           )++instance NFData TarDir++++-- | Where to fetch GHCupDownloads from.+data URLSource+  = GHCupURL+  | StackSetupURL+  | OwnSource [Either (Either GHCupInfo SetupInfo) URI] -- ^ complete source list+  | OwnSpec (Either GHCupInfo SetupInfo)+  | AddSource [Either (Either GHCupInfo SetupInfo) URI] -- ^ merge with GHCupURL+  | SimpleList [NewURLSource]+  deriving (Eq, GHC.Generic, Show)++data NewURLSource+  = NewGHCupURL+  | NewStackSetupURL+  | NewGHCupInfo GHCupInfo+  | NewSetupInfo SetupInfo+  | NewURI URI+  | NewChannelAlias ChannelAlias+  deriving (Eq, GHC.Generic, Show)++instance NFData NewURLSource++-- | Alias for ease of URLSource selection+data ChannelAlias+  = DefaultChannel+  | StackChannel+  | CrossChannel+  | PrereleasesChannel+  | VanillaChannel+  | ThirdPartyChannel+  deriving (Bounded, Enum, Eq, GHC.Generic, Show)++channelAliasText :: ChannelAlias -> Text+channelAliasText DefaultChannel     = "default"+channelAliasText StackChannel       = "stack"+channelAliasText CrossChannel       = "cross"+channelAliasText PrereleasesChannel = "prereleases"+channelAliasText VanillaChannel     = "vanilla"+channelAliasText ThirdPartyChannel  = "3rdparty"++fromURLSource :: URLSource -> [NewURLSource]+fromURLSource GHCupURL             = [NewGHCupURL]+fromURLSource StackSetupURL        = [NewStackSetupURL]+fromURLSource (OwnSource arr)      = convert' <$> arr+fromURLSource (AddSource arr)      = NewGHCupURL:(convert' <$> arr)+fromURLSource (SimpleList arr)     = arr+fromURLSource (OwnSpec (Left gi))  = [NewGHCupInfo gi]+fromURLSource (OwnSpec (Right si)) = [NewSetupInfo si]++convert' :: Either (Either GHCupInfo SetupInfo) URI -> NewURLSource+convert' (Left (Left gi))  = NewGHCupInfo gi+convert' (Left (Right si)) = NewSetupInfo si+convert' (Right uri)       = NewURI uri++instance NFData URLSource+instance NFData ChannelAlias+instance NFData (URIRef Absolute) where+  rnf (URI !_ !_ !_ !_ !_) = ()+++data MetaMode+  = Strict+  | Lax+  deriving (Eq, GHC.Generic, Read, Show)++instance NFData MetaMode++newtype Verbosity = Verbosity Int+  deriving (Eq, GHC.Generic, Show)++instance NFData Verbosity++-- If you add, remove, or rename any fields,+-- make sure to update the GHCup.OptParse.Reset module as well.+data UserSettings = UserSettings+  { uCache :: Maybe Bool+  , uMetaCache :: Maybe Integer+  , uMetaMode :: Maybe MetaMode+  , uNoVerify :: Maybe Bool+  , uVerbose :: Maybe Verbosity+  , uKeepDirs :: Maybe KeepDirs+  , uDownloader :: Maybe Downloader+  , uKeyBindings :: Maybe UserKeyBindings+  , uUrlSource :: Maybe URLSource+  , uNoNetwork :: Maybe Bool+  , uGPGSetting :: Maybe GPGSetting+  , uPlatformOverride :: Maybe PlatformRequest+  , uMirrors :: Maybe DownloadMirrors+  , uDefGHCConfOptions :: Maybe [String]+  , uPager :: Maybe PagerConfig+  , uGuessVersion :: Maybe Bool+  , uBuildWrapper :: Maybe ProcessSpec+  }+  deriving (Eq, GHC.Generic, Show)++defaultUserSettings :: UserSettings+defaultUserSettings = UserSettings Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing++fromSettings :: Settings -> Maybe KeyBindings -> UserSettings+fromSettings Settings{..} Nothing =+  UserSettings {+      uCache = Just cache+    , uMetaCache = Just metaCache+    , uMetaMode = Just metaMode+    , uNoVerify = Just noVerify+    , uVerbose = Just verbose+    , uKeepDirs = Just keepDirs+    , uDownloader = Just downloader+    , uNoNetwork = Just noNetwork+    , uKeyBindings = Nothing+    , uUrlSource = Just (SimpleList urlSource)+    , uGPGSetting = Just gpgSetting+    , uPlatformOverride = platformOverride+    , uMirrors = Just mirrors+    , uDefGHCConfOptions = Just defGHCConfOptions+    , uPager = Just pager+    , uGuessVersion = Just guessVersion+    , uBuildWrapper = buildWrapper+  }+fromSettings Settings{..} (Just KeyBindings{..}) =+  let ukb = UserKeyBindings+            { kUp           = Just bUp+            , kDown         = Just bDown+            , kLeft         = Just bLeft+            , kRight        = Just bRight+            , kTab          = Just bTab+            , kQuit         = Just bQuit+            , kInstall      = Just bInstall+            , kUninstall    = Just bUninstall+            , kSet          = Just bSet+            , kChangelog    = Just bChangelog+            , kShowAll      = Just bShowAllVersions+            }+  in UserSettings {+      uCache = Just cache+    , uMetaCache = Just metaCache+    , uMetaMode = Just metaMode+    , uNoVerify = Just noVerify+    , uVerbose = Just verbose+    , uKeepDirs = Just keepDirs+    , uDownloader = Just downloader+    , uNoNetwork = Just noNetwork+    , uKeyBindings = Just ukb+    , uUrlSource = Just (SimpleList urlSource)+    , uGPGSetting = Just gpgSetting+    , uPlatformOverride = platformOverride+    , uMirrors = Just mirrors+    , uDefGHCConfOptions = Just defGHCConfOptions+    , uPager = Just pager+    , uGuessVersion = Just guessVersion+    , uBuildWrapper = buildWrapper+  }++data UserKeyBindings = UserKeyBindings+  { kUp :: Maybe KeyCombination+  , kDown :: Maybe KeyCombination+  , kLeft :: Maybe KeyCombination+  , kRight :: Maybe KeyCombination+  , kTab :: Maybe KeyCombination+  , kQuit :: Maybe KeyCombination+  , kInstall :: Maybe KeyCombination+  , kUninstall :: Maybe KeyCombination+  , kSet :: Maybe KeyCombination+  , kChangelog :: Maybe KeyCombination+  , kShowAll :: Maybe KeyCombination+  }+  deriving (Eq, GHC.Generic, Show)++data KeyBindings = KeyBindings+  { bUp :: KeyCombination+  , bDown :: KeyCombination+  , bLeft :: KeyCombination+  , bRight :: KeyCombination+  , bTab :: KeyCombination+  , bQuit :: KeyCombination+  , bInstall :: KeyCombination+  , bUninstall :: KeyCombination+  , bSet :: KeyCombination+  , bChangelog :: KeyCombination+  , bShowAllVersions :: KeyCombination+  }+  deriving (GHC.Generic, Show)++instance NFData KeyBindings+#if !defined(BRICK)+instance NFData Key++instance NFData Modifier++#endif+instance NFData KeyCombination++defaultKeyBindings :: KeyBindings+defaultKeyBindings = KeyBindings+  { bUp              = KeyCombination { key = KUp        , mods = [] }+  , bDown            = KeyCombination { key = KDown      , mods = [] }+  , bLeft            = KeyCombination { key = KLeft      , mods = [] }+  , bRight           = KeyCombination { key = KRight     , mods = [] }+  , bTab             = KeyCombination { key = KChar '\t' , mods = [] }+  , bQuit            = KeyCombination { key = KChar 'q'  , mods = [] }+  , bInstall         = KeyCombination { key = KChar 'i'  , mods = [] }+  , bUninstall       = KeyCombination { key = KChar 'u'  , mods = [] }+  , bSet             = KeyCombination { key = KChar 's'  , mods = [] }+  , bChangelog       = KeyCombination { key = KChar 'c'  , mods = [] }+  , bShowAllVersions = KeyCombination { key = KChar 'a'  , mods = [] }+  }++data AppState = AppState+  { settings :: Settings+  , dirs :: Dirs+  , keyBindings :: KeyBindings+  , ghcupInfo :: GHCupInfo+  , pfreq :: PlatformRequest+  , loggerConfig :: LoggerConfig+  }+  deriving (GHC.Generic, Show)++instance NFData AppState++fromAppState :: AppState -> LeanAppState+fromAppState AppState {..} = LeanAppState {..}++data LeanAppState = LeanAppState+  { settings :: Settings+  , dirs :: Dirs+  , keyBindings :: KeyBindings+  , pfreq :: PlatformRequest+  , loggerConfig :: LoggerConfig+  }+  deriving (GHC.Generic, Show)++instance NFData LeanAppState+++data Settings = Settings+  { cache :: Bool+  , metaCache :: Integer+  , metaMode :: MetaMode+  , noVerify :: Bool+  , keepDirs :: KeepDirs+  , downloader :: Downloader+  , verbose :: Verbosity+  , urlSource :: [NewURLSource]+  , noNetwork :: Bool+  , gpgSetting :: GPGSetting+  , noColor :: Bool+    -- this also exists in LoggerConfig+  , platformOverride :: Maybe PlatformRequest+  , mirrors :: DownloadMirrors+  , defGHCConfOptions :: [String]+  , pager :: PagerConfig+  , guessVersion :: Bool+  , buildWrapper :: Maybe ProcessSpec+  }+  deriving (GHC.Generic, Show)++data ProcessSpec = ProcessSpec+  { cmd :: String+  , cmdArgs :: [String]+  }+  deriving (Eq, GHC.Generic, Show)++instance NFData ProcessSpec++data PagerConfig = PagerConfig+  { pagerList :: Bool+  , pagerCmd :: Maybe String+  }+  deriving (Eq, GHC.Generic, Show)++instance NFData PagerConfig++defaultPagerConfig :: PagerConfig+defaultPagerConfig = PagerConfig False Nothing++allPagerConfig :: String -> PagerConfig+allPagerConfig cmd = PagerConfig True (Just cmd)++defaultMetaCache :: Integer+defaultMetaCache = 300 -- 5 minutes++defaultSettings :: Settings+defaultSettings = Settings False defaultMetaCache Lax False Never Curl (Verbosity 0) [NewGHCupURL] False GPGNone False Nothing (DM mempty) [] defaultPagerConfig True Nothing++instance NFData Settings++data Dirs = Dirs+  { baseDir :: GHCupPath+  , binDir :: FilePath+  , cacheDir :: GHCupPath+  , logsDir :: GHCupPath+  , confDir :: GHCupPath+  , dbDir :: GHCupPath+  , recycleDir :: GHCupPath+    -- mainly used on windows+  , tmpDir :: GHCupPath+  , msys2Dir :: FilePath+  }+  deriving (GHC.Generic, Show)++instance NFData Dirs++data MSYS2Env+  = MSYS+  | UCRT64+  | CLANG64+  | CLANGARM64+  | CLANG32+  | MINGW64+  | MINGW32+  deriving (Eq, GHC.Generic, Ord, Read, Show)++instance NFData MSYS2Env++data KeepDirs+  = Always+  | Errors+  | Never+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData KeepDirs++data Downloader = Curl+                | Wget+#if defined(INTERNAL_DOWNLOADER)+                | Internal+#endif+  deriving (Eq, Show, Ord, GHC.Generic)++instance NFData Downloader++data GPGSetting+  = GPGStrict+  | GPGLax+  | GPGNone+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData GPGSetting++data DebugInfo = DebugInfo+  { diDirs :: Dirs+  , diArch :: Architecture+  , diPlatform :: PlatformResult+  , diChannels :: [(ChannelAlias, URI)]+  , diShimGenURL :: URI+  }+  deriving (Show)+++data SetGHC+  = SetGHCOnly -- ^ unversioned 'ghc'+  | SetGHC_XY -- ^ ghc-x.y+  | SetGHC_XYZ -- ^ ghc-x.y.z+  deriving (Eq, Show)++data SetHLS+  = SetHLSOnly -- ^ unversioned 'hls'+  | SetHLS_XYZ -- ^ haskell-language-server-a.b.c~x.y.z, where a.b.c is GHC version and x.y.z is HLS version+  deriving (Eq, Show)+++data PlatformResult = PlatformResult+  { _platform :: Platform+  , _distroVersion :: Maybe Versioning+  }+  deriving (Eq, GHC.Generic, Show)++instance NFData PlatformResult++platResToString :: PlatformResult -> String+platResToString PlatformResult { _platform = plat, _distroVersion = Just v' }+  = show plat <> ", " <> T.unpack (prettyV v')+platResToString PlatformResult { _platform = plat, _distroVersion = Nothing }+  = show plat++instance Pretty PlatformResult where+  pPrint = text . platResToString++data PlatformRequest = PlatformRequest+  { _rArch :: Architecture+  , _rPlatform :: Platform+  , _rVersion :: Maybe Versioning+  }+  deriving (Eq, GHC.Generic, Show)++instance NFData PlatformRequest++pfReqToString :: PlatformRequest -> String+pfReqToString (PlatformRequest arch plat ver) =+  archToString arch ++ "-" ++ platformToString plat ++ pver+ where+  pver = case ver of+           Just v' -> "-" ++ T.unpack (prettyV v')+           Nothing -> ""++instance Pretty PlatformRequest where+  pPrint = text . pfReqToString++-- | A version with a revision, denoting bindist 'versions' that are purely distribution specific.+--+-- The revision starts at 0.+data VersionRev = VersionRev+  { _vrVersion :: Version+  , _vrRev :: Int+  }+  deriving (Ord, Eq, GHC.Generic, Show)++instance NFData VersionRev++data VersionReq = VersionReq+  { _vqVersion :: Version+  , _vqRev       :: Maybe Int+  }+  deriving (Ord, Eq, Show)++instance Pretty VersionReq where+  pPrint (VersionReq tver Nothing) = pPrint tver+  pPrint (VersionReq tver (Just rev)) = pPrint tver <> "-r" <> text (show rev)++mkVersionRev :: Version -> VersionRev+mkVersionRev v = VersionRev v 0++prettyVerRev :: VersionRev -> Text+prettyVerRev VersionRev{..} = prettyVer _vrVersion <> "-r" <> T.pack (show _vrRev)++-- | A GHC identified by the target platform triple+-- and the version.+data TargetVersion = TargetVersion+  { _tvTarget :: Maybe Text+  , _tvVersion :: Version+  }+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData TargetVersion++-- | A GHC identified by the target platform triple+-- and the version.+data TargetVersionRev = TargetVersionRev+  { _tvrTargetVer :: TargetVersion+  , _tvrRev       :: Int+  }+  deriving (Ord, Eq, Show)++instance Pretty TargetVersionRev where+  pPrint (TargetVersionRev tver rev) = text $ T.unpack (tVerToText tver) <> "-r" <> show rev++toTargetVersionReq'' :: Version -> TargetVersionReq+toTargetVersionReq'' v = TargetVersionReq (TargetVersion Nothing v) Nothing++toTargetVersionReq' :: VersionReq -> TargetVersionReq+toTargetVersionReq' (VersionReq v' rev) = TargetVersionReq (TargetVersion Nothing v') rev++toVersionReq' :: TargetVersionReq -> VersionReq+toVersionReq' (TargetVersionReq (TargetVersion _ v') rev) = VersionReq v' rev++unsafeToTargetVersionRev :: TargetVersion -> TargetVersionRev+unsafeToTargetVersionRev tv = TargetVersionRev tv 0++unsafeToTargetVersionReq :: TargetVersion -> TargetVersionReq+unsafeToTargetVersionReq tv = TargetVersionReq tv (Just 0)++data TargetVersionReq = TargetVersionReq+  { _tvqTargetVer :: TargetVersion+  , _tvqRev       :: Maybe Int+  }+  deriving (Ord, Eq, Show)++instance Pretty TargetVersionReq where+  pPrint (TargetVersionReq tver Nothing) = pPrint tver+  pPrint (TargetVersionReq tver (Just rev)) = text $ T.unpack (tVerToText tver) <> "-r" <> show rev++reqTV :: TargetVersionRev -> TargetVersionReq+reqTV TargetVersionRev{..} = TargetVersionReq _tvrTargetVer (Just _tvrRev)++data GitBranch = GitBranch+  { ref :: String+  , repo :: Maybe String+  }++  deriving (Eq, Ord, Show)++mkTVer :: Version -> TargetVersion+mkTVer = TargetVersion Nothing++unsafeMkTVerRev :: Version -> TargetVersionRev+unsafeMkTVerRev v' = TargetVersionRev (mkTVer v') 0++tVerToText :: TargetVersion -> Text+tVerToText (TargetVersion (Just t) v') = t <> "-" <> prettyVer v'+tVerToText (TargetVersion Nothing  v') = prettyVer v'++tVerRevToText :: TargetVersionRev -> Text+tVerRevToText (TargetVersionRev tv rev) = tVerToText tv <> "-r" <> T.pack (show rev)++-- | Assembles a path of the form: <target-triple>-<version>+instance Pretty TargetVersion where+  pPrint = text . T.unpack . tVerToText+++-- | A comparator and a version.+data VersionCmp+  = VR_gt Versioning+  | VR_gteq Versioning+  | VR_lt Versioning+  | VR_lteq Versioning+  | VR_eq Versioning+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData VersionCmp++-- | A version range. Supports && and ||, but not  arbitrary+-- combinations. This is a little simplified.+data VersionRange+  = SimpleRange (NonEmpty VersionCmp) -- And+  | OrRange (NonEmpty VersionCmp) VersionRange+  deriving (Eq, GHC.Generic, Ord, Show)++instance NFData VersionRange++instance Pretty VersionCmp where+  pPrint (VR_gt v)   = text "> " <> pPrint v+  pPrint (VR_gteq v) = text ">= " <> pPrint v+  pPrint (VR_lt v)   = text "< " <> pPrint v+  pPrint (VR_lteq v) = text "<= " <> pPrint v+  pPrint (VR_eq v)   = text "= " <> pPrint v++instance Pretty VersionRange where+  pPrint (SimpleRange xs) = foldl1 (\x y -> x <> text " && " <> y) $ NE.map pPrint xs+  pPrint (OrRange xs vr) = foldMap pPrint xs <> " || " <> pPrint vr++instance Pretty Versioning where+  pPrint = text . T.unpack . prettyV++instance Pretty Version where+  pPrint = text . T.unpack . prettyVer++instance Show (a -> b) where+  show _ = "<function>"++instance Show (IO ()) where+  show _ = "<io>"+++data LogLevel+  = Warn+  | Info+  | Debug Int+  | Error+  deriving (Eq, Ord, Show)++data LoggerConfig = LoggerConfig+  { lcPrintDebugLvl :: Maybe Int+    -- ^ 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 !_ !_ !fancyColors) = rnf (lcPrintDebug, fancyColors)++data ProcessError+  = NonZeroExit Int FilePath [String]+  | PTerminated FilePath [String]+  | PStopped FilePath [String]+  | NoSuchPid FilePath [String]+  deriving (Show)+++data CapturedProcess = CapturedProcess+  { _exitCode :: ExitCode+  , _stdOut :: BL.ByteString+  , _stdErr :: BL.ByteString+  }+  deriving (Eq, Show)++++data InstallDir+  = IsolateDir FilePath+  | GHCupInternal+  deriving (Eq, Show)++data InstallDirResolved+  = IsolateDirResolved FilePath+  | GHCupDir GHCupPath+  | GHCupBinDir FilePath+  deriving (Eq, Show)++fromInstallDir :: InstallDirResolved -> FilePath+fromInstallDir (IsolateDirResolved fp) = fp+fromInstallDir (GHCupDir fp)           = fromGHCupPath fp+fromInstallDir (GHCupBinDir fp)        = fp+++isSafeDir :: InstallDirResolved -> Bool+isSafeDir (IsolateDirResolved _) = False+isSafeDir (GHCupDir _)           = True+isSafeDir (GHCupBinDir _)        = False++type PromptQuestion = Text++data PromptResponse+  = PromptYes+  | PromptNo+  deriving (Eq, Show)++data ToolVersion+  = GHCVersion TargetVersionReq+  | ToolVersion VersionReq+  | ToolTag Tag+  | ToolDay Day+  deriving (Eq, Show)++instance Pretty ToolVersion where+  pPrint (GHCVersion v)  = pPrint v+  pPrint (ToolVersion v) = pPrint v+  pPrint (ToolTag t)     = pPrint t+  pPrint (ToolDay d)     = text (show d)++++data BuildSystem+  = Hadrian+  | Make+  deriving (Eq, Show)+++data VersionPattern+  = CabalVer+  | GitHashShort+  | GitHashLong+  | GitDescribe+  | GitBranchName+  | S String+  deriving (Eq, Show)++-- | Map with custom FromJSON instance which ignores unknown keys+newtype MapIgnoreUnknownKeys k v+  = MapIgnoreUnknownKeys { unMapIgnoreUnknownKeys :: Map k v }+  deriving (Eq, GHC.Generic, Ord, Show)++instance (NFData k, NFData v) => NFData (MapIgnoreUnknownKeys k v)++-- | Type representing our guessing modes when e.g. "incomplete" PVP version+-- is specified, such as @ghcup set ghc 9.12@.+data GuessMode+  = GStrict -- ^ don't guess the proper tool version+  | GLax -- ^ guess by using the metadata+  | GLaxWithInstalled -- ^ guess by using metadata and installed versions+  deriving (Eq, Show)++data ShowRevisions = ShowUpdates+                   | ShowAll+                   | ShowNone   deriving (Eq, Show) 
+ lib/GHCup/Types/Dhall.hs view
@@ -0,0 +1,429 @@+{-# OPTIONS_GHC -Wno-orphans #-}++{-# LANGUAGE CPP #-}+#if defined(DHALL)+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-}+#endif++{-|+Module      : GHCup.Types.Dhall+Description : GHCup Dhall instances+Copyright   : (c) Julian Ospald, 2020+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Types.Dhall () where++#if defined(DHALL)++import           Dhall+    ( DhallErrors (..)+    , ExtractError (..)+    , Extractor+    , FromDhall (autoWith)+    , ToDhall (injectWith)+    , InterpretOptions (fieldModifier, singletonConstructors)+    , defaultInterpretOptions+    , genericToDhallWithInputNormalizer+    , extract+    , fromMonadic+    , genericAutoWith+    , toMonadic, SingletonConstructors (Bare)+    )+import qualified Dhall+import           GHCup.Types+import           GHCup.Prelude+import           GHCup.Types.JSON+    (verRangeToText)+import           GHCup.Types.Stack+    ()++import           Data.Versions            ( PVP, Version, pvp', version', prettyPVP, prettyVer, pvp )+import           Data.Void                ( Void )+import           GHCup.Prelude.MegaParsec ( ghcTargetVerP, versionRangeP )+import qualified Text.Megaparsec          as MP++import           Control.Applicative     ( (<|>) )+import           Data.Aeson              ( decodeStrict )+import Data.Map.Strict                ( Map )+import           Data.Bifunctor          ( first )+import           Data.Functor            ( ($>) )+import qualified Data.List.NonEmpty      as NE+import           Data.Maybe              ( fromJust )+import qualified Data.Text               as T+import           Data.Text.Encoding      as E+import           Dhall.Core              ( Expr )+import qualified Dhall.Core+import           Dhall.Parser            ( Src )+import           GHCup.Input.Parsers.URI ( parseURI' )+import           URI.ByteString          ( URI, serializeURIRef' )+import Text.PrettyPrint.HughesPJClass (prettyShow)+import Text.Read (readMaybe)+import qualified Data.Map.Strict as M+import qualified Dhall.Map+++pattern DhallString :: T.Text -> Expr s a+pattern DhallString t = Dhall.Core.TextLit (Dhall.Core.Chunks [] t)+++instance FromDhall VersionRange where+  autoWith _ =+    Dhall.string+      { extract = extractParser versionRangeP+      }++instance ToDhall VersionRange where+  injectWith _ = Dhall.Encoder+    { embed = \(verRangeToText -> t) -> DhallString t+    , declared = Dhall.Core.Text+    }++instance FromDhall Architecture where+  autoWith _ = genericAutoWith defaultInterpretOptions++instance ToDhall Architecture where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions++instance {-# OVERLAPPING #-} FromDhall Platform where+  autoWith _ =+    Dhall.string+      { extract = extractParser' parsePlatform+      }+   where+    parsePlatform t+      | "Darwin"  == t = Right Darwin+      | "FreeBSD" == t = Right FreeBSD+      | "OpenBSD" == t = Right OpenBSD+      | "Windows" == t = Right Windows+      | "Linux_" `T.isPrefixOf` t = case+          T.stripPrefix (T.pack "Linux_") t+        of+          Just dstr ->+            case+                (decodeStrict (E.encodeUtf8 (T.pack "\"" <> dstr <> T.pack "\"")) :: Maybe+                    LinuxDistro+                )+              of+                Just d -> Right $ Linux d+                Nothing ->+                  Left+                    $  "Unexpected failure in decoding LinuxDistro: "+                    <> show dstr+          Nothing -> Left "Unexpected failure in Platform stripPrefix"+      | otherwise = Left "Failure in Platform (FromJSONKey)"++instance ToDhall Platform where+  injectWith _ = Dhall.Encoder+    { embed = \case+                 Darwin  -> DhallString "Darwin"+                 FreeBSD -> DhallString "FreeBSD"+                 Linux d -> DhallString ("Linux_" <> T.pack (show d))+                 OpenBSD -> DhallString "OpenBSD"+                 Windows -> DhallString "Windows"+    , declared = Dhall.Core.Text+    }++instance {-# OVERLAPPING #-} FromDhall (Maybe VersionRange) where+  autoWith _ =+    Dhall.string+      { extract = extractParser (MP.chunk "unknown_versioning" $> Nothing <|> (Just <$> versionRangeP))+      }++instance {-# OVERLAPPING #-} ToDhall (Maybe VersionRange) where+  injectWith _ = Dhall.Encoder+    { embed = \case+                Just t -> Dhall.embed @VersionRange Dhall.inject $ t+                Nothing ->  DhallString "unknown_versioning"+    , declared = Dhall.Core.Text+    }++instance FromDhall PVP where+  autoWith _ =+    Dhall.string+      { extract = extractParser pvp'+      }++instance ToDhall PVP where+  injectWith _ = Dhall.Encoder+    { embed = \(prettyPVP -> t) -> DhallString t+    , declared = Dhall.Core.Text+    }++instance {-# OVERLAPPING #-} FromDhall (Maybe Version) where+  autoWith _ =+    Dhall.string+      { extract = extractParser (MP.chunk "unknown_version" $> Nothing <|> (Just <$> version'))+      }++instance ToDhall Version where+  injectWith _ = Dhall.Encoder+    { embed = \(prettyVer -> t) -> DhallString t+    , declared = Dhall.Core.Text+    }++instance {-# OVERLAPPING #-} ToDhall (Maybe Version) where+  injectWith _ = Dhall.Encoder+    { embed = \case+                Just t -> Dhall.embed @Version Dhall.inject $ t+                Nothing -> DhallString "unknown_version"+    , declared = Dhall.Core.Text+    }++instance FromDhall TargetVersion where+  autoWith _ =+    Dhall.string+      { extract = extractParser ghcTargetVerP+      }++instance ToDhall TargetVersion where+  injectWith _ = Dhall.Encoder+    { embed = \(T.pack . prettyShow -> t) -> DhallString t+    , declared = Dhall.Core.Text+    }++extractParser :: forall a. MP.Parsec Void T.Text a -> Expr Src Void -> Extractor Src Void a+extractParser parser = extractParser' (MP.parse parser "FromDhall")++extractParser' :: forall a e. Show e => (T.Text -> Either e a) -> Expr Src Void -> Extractor Src Void a+extractParser' parse expr = fromMonadic $ do+  t <- toMonadic $ extract Dhall.string expr+  first (DhallErrors . NE.singleton . ExtractError . T.pack . show) . parse . T.pack $ t++instance FromDhall Tag where+  autoWith _ = Dhall.string+    { extract = \case+        DhallString "Latest"                             -> pure Latest+        DhallString "Recommended"                        -> pure Recommended+        DhallString "Prerelease"                         -> pure Prerelease+        DhallString "Nightly"                            -> pure Nightly+        DhallString "LatestPrerelease"                   -> pure LatestPrerelease+        DhallString "LatestNightly"                      -> pure LatestNightly+        DhallString "Experimental"                       -> pure Experimental+        DhallString "old"                                -> pure Old+        e@(DhallString (T.unpack -> 'b' : 'a' : 's' : 'e' : '-' : ver')) -> case pvp (T.pack ver') of+          Right x -> pure $ Base x+          Left  _ -> Dhall.typeError (Dhall.expected Dhall.string) e+        DhallString x -> pure (UnknownTag $ T.unpack x)+        e -> Dhall.typeError (Dhall.expected Dhall.string) e+    }++instance ToDhall Tag where+  injectWith _ = Dhall.Encoder+    { embed = \case+        Latest             -> DhallString "Latest"+        Recommended        -> DhallString "Recommended"+        Prerelease         -> DhallString "Prerelease"+        Nightly            -> DhallString "Nightly"+        Old                -> DhallString "old"+        (Base       pvp'') -> DhallString ("base-" <> prettyPVP pvp'')+        LatestPrerelease   -> DhallString "LatestPrerelease"+        LatestNightly      -> DhallString "LatestNightly"+        Experimental       -> DhallString "Experimental"+        (UnknownTag x    ) -> DhallString (T.pack x)+    , declared = Dhall.Core.Text+    }++instance FromDhall URI where+  autoWith _ =+    Dhall.string+      { extract = extractParser' parseURI'+      }++instance ToDhall URI where+  injectWith _ = Dhall.Encoder+    { embed = \(decUTF8Safe . serializeURIRef' -> uri) -> DhallString uri+    , declared = Dhall.Core.Text+    }++fieldModifierLowerCase :: Int -> T.Text -> T.Text+fieldModifierLowerCase i = (\(c, t) -> T.singleton (lower c) <> t) . fromJust . T.uncons . T.drop i++instance FromDhall InstallFileRule where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 4 }++instance ToDhall InstallFileRule where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 4 }++instance FromDhall (SymlinkSpec String) where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 3 }++instance ToDhall (SymlinkSpec String) where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 3 }++instance FromDhall SymlinkInputSpec where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 3 }++instance ToDhall SymlinkInputSpec where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 3 }++instance FromDhall Rev where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { singletonConstructors = Bare }++instance ToDhall Rev where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { singletonConstructors = Bare }++instance FromDhall RevisionSpec where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { singletonConstructors = Bare }++instance ToDhall RevisionSpec where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { singletonConstructors = Bare }++instance FromDhall ToolInfo where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 1 }++instance ToDhall ToolInfo where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 1 }++instance FromDhall ToolDescription where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 1 }++instance ToDhall ToolDescription where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 1 }++instance FromDhall EnvSpec where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 3 }++instance ToDhall EnvSpec where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 3 }++instance FromDhall ConfigSpec where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 3 }++instance ToDhall ConfigSpec where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 3 }++instance FromDhall MakeSpec where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 3 }++instance ToDhall MakeSpec where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 3 }++instance FromDhall a => FromDhall (InstallationSpecGen a) where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 3 }++instance ToDhall a => ToDhall (InstallationSpecGen a) where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 3 }++instance FromDhall DownloadInfo where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 1 }++instance ToDhall DownloadInfo where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 1 }++instance (Ord k, FromDhall k, FromDhall v) => FromDhall (MapIgnoreUnknownKeys k v) where+  autoWith opts = MapIgnoreUnknownKeys <$> autoWith opts++instance (Ord k, ToDhall k, ToDhall v) => ToDhall (MapIgnoreUnknownKeys k v) where+  injectWith opts = Dhall.Encoder+    { embed = \(MapIgnoreUnknownKeys m) -> Dhall.embed Dhall.inject $ m+    , declared = Dhall.declared enc+    }+   where+    enc = Dhall.injectWith opts :: Dhall.Encoder (Map k v)++instance FromDhall VersionInfo where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 1 }++instance ToDhall VersionInfo where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 1 }++instance FromDhall Requirements where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 1 }++instance ToDhall Requirements where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 1 }++instance FromDhall GHCupInfo where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 1 }++instance ToDhall GHCupInfo where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 1 }++instance FromDhall PlatformVersionSpec where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { singletonConstructors = Bare }++instance ToDhall PlatformVersionSpec where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { singletonConstructors = Bare }++instance FromDhall PlatformSpec where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { singletonConstructors = Bare }++instance ToDhall PlatformSpec where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { singletonConstructors = Bare }++instance FromDhall ArchitectureSpec where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { singletonConstructors = Bare }++instance ToDhall ArchitectureSpec where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { singletonConstructors = Bare }++instance FromDhall ToolVersionSpec where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { singletonConstructors = Bare }++instance ToDhall ToolVersionSpec where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { singletonConstructors = Bare }++instance FromDhall GHCupDownloads where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { singletonConstructors = Bare }++instance ToDhall GHCupDownloads where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { singletonConstructors = Bare }++instance FromDhall VersionMetadata where+  autoWith _ = genericAutoWith defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 3 }++instance ToDhall VersionMetadata where+  injectWith = genericToDhallWithInputNormalizer defaultInterpretOptions+    { fieldModifier = fieldModifierLowerCase 3 }++#endif
lib/GHCup/Types/JSON.hs view
@@ -1,14 +1,15 @@ {-# OPTIONS_GHC -Wno-orphans #-} -{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE DeriveGeneric         #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE QuasiQuotes           #-}-{-# LANGUAGE TemplateHaskell       #-}-{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}  {-| Module      : GHCup.Types.JSON@@ -21,55 +22,158 @@ -} module GHCup.Types.JSON where -import           GHCup.Types-import           GHCup.Types.Stack (SetupInfo)-import           GHCup.Types.JSON.MapIgnoreUnknownKeys ()-import           GHCup.Types.JSON.Utils-import           GHCup.Types.JSON.Versions ()-import           GHCup.Prelude.MegaParsec-import           GHCup.Utils.URI+import GHCup.Input.Parsers.URI+import GHCup.Prelude.JSON+import GHCup.Prelude.MegaParsec+import GHCup.Types+import GHCup.Types.JSON.MapIgnoreUnknownKeys+    ()+import GHCup.Types.JSON.Utils+import GHCup.Types.JSON.Versions+    ()+import GHCup.Types.Stack                     ( SetupInfo ) -import           Control.Applicative            ( (<|>) )-import           Data.Aeson              hiding (Key)-import           Data.Aeson.TH-import           Data.Aeson.Types        hiding (Key)-import           Data.ByteString                ( ByteString )-import           Data.List.NonEmpty             ( NonEmpty(..) )-import           Data.Maybe-import           Data.Text.Encoding            as E-import           Data.Foldable-import           Data.Versions-import           Data.Void-import           URI.ByteString hiding (parseURI)-import           Text.Casing+import Control.Applicative ( (<|>) )+import Control.Monad+import Data.Aeson          hiding ( Key )+import Data.Aeson.TH+import Data.Aeson.Types    hiding ( Key )+import Data.ByteString     ( ByteString )+import Data.Foldable+import Data.Maybe+import Data.Scientific (toBoundedInteger)+import Data.Text.Encoding  as E+import Data.Versions+import System.FilePath     ( hasDrive, isAbsolute, splitPath )+import Text.Casing+import URI.ByteString      hiding ( parseURI ) -import qualified Data.List.NonEmpty            as NE-import qualified Data.Text                     as T-import qualified Data.Text.Encoding.Error      as E-import qualified Text.Megaparsec               as MP-import qualified Text.Megaparsec.Char          as MPC+import qualified Data.Map.Strict          as M+import qualified Data.List.NonEmpty       as NE+import qualified Data.Text                as T+import qualified Data.Text.Encoding.Error as E+import qualified Text.Megaparsec          as MP+import qualified Text.Megaparsec.Char.Lexer as L+import Data.Functor.Contravariant (Contravariant(contramap)) +safePath :: FilePath -> Bool+safePath fp+  | "." `notElem` fp'+  , ".." `notElem` fp'+  , not (hasDrive fp)+  , not (isAbsolute fp)+  = True+  | otherwise = False+ where+  fp' = splitPath fp++checkSafePath :: MonadFail m => FilePath -> m ()+checkSafePath fp = unless (safePath fp) $ fail "'..' or '.' are not allowed"++safeFilename :: FilePath -> Bool+safeFilename fp+  | length fp' == 1+  , "." `notElem` fp'+  , ".." `notElem` fp'+  , not (hasDrive fp)+  , not (isAbsolute fp)+  = True+  | otherwise = False+ where+  fp' = splitPath fp++checkSafeFilename :: MonadFail m => FilePath -> m ()+checkSafeFilename fp = unless (safeFilename fp) $ fail "'..' or '.' are not allowed and filepath must have no path separators"++safeVersion :: TargetVersion -> Bool+safeVersion TargetVersion{..}+  | pver `notElem` ["db", "set", "ghc", "cabal", "stack", "hls", "ghcup"]+  , pver' `notElem` cabalBadNames+  , safeFilename pver'+  , maybe True (`notElem` ["db", "set", "ghc", "cabal", "stack", "hls", "ghcup"]) _tvTarget+  , maybe True (safeFilename . T.unpack) _tvTarget+  , Left _ <- hasRev pver+  = True+  | otherwise = False+ where+  pver = prettyVer _tvVersion+  pver' = T.unpack $ prettyVer _tvVersion+  hasRev = MP.parse hasRevP "hasRev"+  hasRevP = do+    _ <- parseUntilEmpty "-r"+    _ <- MP.chunk "-r" *> (L.decimal @_ @_ @_ @Int)+    pure ()+++-- This is sad, but our version parsers are too lax,+-- so we need to make sure that e.g. 'cabal-audit'+-- is not parser as cabal with version 'audit'.+-- Backwards compatibility is a b*tch.+cabalBadNames :: [String]+cabalBadNames =+  [ "plan"+  , "add"+  , "audit"+  , "bounds"+  , "bundler"+  , "cache"+  , "clean"+  , "core-inspection"+  , "deps"+  , "diff"+  , "docspec"+  , "doctest"+  , "edit"+  , "env"+  , "fmt"+  , "haddock-server"+  , "hasklint"+  , "helper"+  , "hie"+  , "hoogle"+  , "ifacy-query"+  , "progdeps"+  , "sort"+  , "store-check"+  , "store-gc"+  ]+++checkSafeVersion :: MonadFail m => TargetVersion -> m ()+checkSafeVersion v' = unless (safeVersion v') $ fail "Unsafe version, try something more vanilla like '1.2.3'"++safeToolname :: Tool -> Bool+safeToolname (Tool t)+  | t `notElem` ["db", "set", "bin", "cache", "env", "config.yaml", "tmp", "trash", "logs"]+  , safeFilename t+  = True+  | otherwise = False++checkSafeToolname :: MonadFail m => Tool -> m ()+checkSafeToolname t = unless (safeToolname t) $ fail "Unsafe tool name, try something more vanilla"+ instance ToJSON LinuxDistro where   toJSON = String . T.pack . show  instance FromJSON LinuxDistro where   parseJSON = withText "LinuxDistro" $ \t -> case T.unpack (T.toLower t) of-    "debian"   -> pure Debian-    "ubuntu"   -> pure Ubuntu-    "mint"     -> pure Mint-    "fedora"   -> pure Fedora-    "centos"   -> pure CentOS-    "redhat"   -> pure RedHat-    "alpine"   -> pure Alpine-    "amazonlinux" -> pure AmazonLinux-    "rocky"    -> pure Rocky-    "void"     -> pure Void-    "gentoo"   -> pure Gentoo-    "exherbo"  -> pure Exherbo-    "opensuse" -> pure OpenSUSE+    "debian"       -> pure Debian+    "ubuntu"       -> pure Ubuntu+    "mint"         -> pure Mint+    "fedora"       -> pure Fedora+    "centos"       -> pure CentOS+    "redhat"       -> pure RedHat+    "alpine"       -> pure Alpine+    "amazonlinux"  -> pure AmazonLinux+    "rocky"        -> pure Rocky+    "void"         -> pure Void+    "gentoo"       -> pure Gentoo+    "exherbo"      -> pure Exherbo+    "opensuse"     -> pure OpenSUSE     "unknownlinux" -> pure UnknownLinux-    _ -> fail "Unknown Linux distro"+    _              -> fail "Unknown Linux distro" +deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''ProcessSpec deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''MetaMode deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Architecture deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''VSep@@ -79,10 +183,10 @@ deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Chunk deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Release deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''SemVer-deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Tool deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''KeepDirs deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Downloader deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''GPGSetting+deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''EnvUnion deriveJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' T.unpack . T.stripPrefix (T.pack "r-") . T.pack . kebab . tail $ str' } ''PlatformRequest  instance ToJSON Tag where@@ -112,6 +216,15 @@       Left  e -> fail . show $ e     x -> pure (UnknownTag x) +instance ToJSON Tool where+  toJSON (Tool t) = String (T.toLower . T.pack $ t)++instance FromJSON Tool where+  parseJSON = withText "Tool" $ \t -> do+    let tool = Tool . T.unpack . T.toLower $ t+    checkSafeToolname tool+    pure tool+ instance ToJSON URI where   toJSON = toJSON . E.decodeUtf8With E.lenientDecode . serializeURIRef' @@ -122,21 +235,33 @@       Right x -> pure x       Left  e -> fail . show $ e -instance ToJSON GHCTargetVersion where+instance ToJSON TargetVersion where   toJSON = toJSON . tVerToText -instance FromJSON GHCTargetVersion where-  parseJSON = withText "GHCTargetVersion" $ \t -> case MP.parse ghcTargetVerP "" t of-    Right x -> pure x-    Left  e -> fail $ "Failure in GHCTargetVersion (FromJSON)" <> show e+instance FromJSON TargetVersion where+  parseJSON = withText "TargetVersion" $ \t -> case MP.parse ghcTargetVerP "" t of+    Right x -> do+      checkSafeVersion x+      pure x+    Left  e -> fail $ "Failure in TargetVersion (FromJSON)" <> show e -instance ToJSONKey GHCTargetVersion where+instance ToJSONKey TargetVersion where   toJSONKey = toJSONKeyText $ \x -> tVerToText x -instance FromJSONKey GHCTargetVersion where+deriveJSON defaultOptions { unwrapUnaryRecords = True } ''Rev++instance FromJSONKey Rev where+  fromJSONKey = Rev <$> fromJSONKey @Int++instance ToJSONKey Rev where+  toJSONKey = contramap unRev toJSONKey++instance FromJSONKey TargetVersion where   fromJSONKey = FromJSONKeyTextParser $ \t -> case MP.parse ghcTargetVerP "" t of-    Right x -> pure x-    Left  e -> fail $ "Failure in GHCTargetVersion (FromJSONKey)" <> show e+    Right x -> do+      checkSafeVersion x+      pure x+    Left  e -> fail $ "Failure in TargetVersion (FromJSONKey)" <> show e   instance ToJSONKey Platform where@@ -177,23 +302,26 @@   fromJSONKey = genericFromJSONKey defaultJSONKeyOptions  instance ToJSONKey Tool where-  toJSONKey = genericToJSONKey defaultJSONKeyOptions+  toJSONKey = toJSONKeyText $ \(Tool t) -> T.toLower . T.pack $ t  instance FromJSONKey Tool where-  fromJSONKey = genericFromJSONKey defaultJSONKeyOptions+  fromJSONKey = FromJSONKeyTextParser $ \(T.unpack . T.toLower -> t) -> pure (Tool t)  instance ToJSON TarDir where-  toJSON (RealDir  p) = toJSON p+  toJSON (RealDir  p) = object ["RealDir" .= p]   toJSON (RegexDir r) = object ["RegexDir" .= r]  instance FromJSON TarDir where-  parseJSON v = realDir v <|> regexDir v+  parseJSON v = realDir v <|> regexDir v <|> realDirStrict v    where     realDir = withText "TarDir" $ \t -> do       fp <- parseJSON (String t)       pure (RealDir fp)+    realDirStrict = withObject "TarDir" $ \o -> do+      r <- o .:: ["RealDir", "realDir"]+      pure $ RealDir r     regexDir = withObject "TarDir" $ \o -> do-      r <- o .: "RegexDir"+      r <- o .:: ["RegexDir", "regexDir"]       pure $ RegexDir r  @@ -219,18 +347,6 @@ versionCmpToText (VR_lteq ver') = "<= " <> prettyV ver' versionCmpToText (VR_eq   ver') = "== " <> prettyV ver' -versionCmpP :: MP.Parsec Void T.Text VersionCmp-versionCmpP = either (fail . T.unpack) pure =<< (translate <$> (MPC.space *> MP.try (MP.takeWhileP Nothing (`elem` ['>', '<', '=']))) <*> (MPC.space *> versioningEnd))- where-   translate ">" v  = Right $ VR_gt v-   translate ">=" v = Right $ VR_gteq v-   translate "<" v  = Right $ VR_lt v-   translate "<=" v = Right $ VR_lteq v-   translate "==" v = Right $ VR_eq v-   translate "" v   = Right $ VR_eq v-   translate c  _   = Left $ "unexpected comparator: " <> c-- instance ToJSON VersionRange where   toJSON = String . verRangeToText @@ -250,34 +366,7 @@       Right r -> pure r       Left  e -> fail (MP.errorBundlePretty e) -versionRangeP :: MP.Parsec Void T.Text VersionRange-versionRangeP = go <* MP.eof- where-  go =-    MP.try orParse-      <|> MP.try (fmap SimpleRange andParse)-      <|> fmap (SimpleRange . pure) versionCmpP -  orParse :: MP.Parsec Void T.Text VersionRange-  orParse =-    (\a o -> OrRange a o)-      <$> (MP.try andParse <|> fmap pure versionCmpP)-      <*> (MPC.space *> MP.chunk "||" *> MPC.space *> go)--  andParse :: MP.Parsec Void T.Text (NonEmpty VersionCmp)-  andParse =-    fmap (\h t -> h :| t)-         (MPC.space *> MP.chunk "(" *> MPC.space *> versionCmpP)-      <*> MP.try (MP.many (MPC.space *> MP.chunk "&&" *> MPC.space *> versionCmpP))-      <*  MPC.space-      <*  MP.chunk ")"-      <*  MPC.space--versioningEnd :: MP.Parsec Void T.Text Versioning-versioningEnd =-  MP.try (verP (MP.chunk " " <|> MP.chunk ")" <|> MP.chunk "&&") <* MPC.space)-    <|> versioning'- instance ToJSONKey (Maybe VersionRange) where   toJSONKey = toJSONKeyText $ \case     Just x -> verRangeToText x@@ -291,26 +380,230 @@       Right x -> pure $ Just x       Left  e -> fail $ "Failure in (Maybe VersionRange) (FromJSONKey)" <> MP.errorBundlePretty e +deriveToJSON defaultOptions { fieldLabelModifier = mapHead lower . drop 3 } ''SymlinkSpec+deriveToJSON defaultOptions { fieldLabelModifier = mapHead lower . drop 3+                            , sumEncoding = UntaggedValue+                            } ''SymlinkInputSpec+deriveToJSON defaultOptions { fieldLabelModifier = mapHead lower . drop 4+                            , sumEncoding = UntaggedValue+                            } ''InstallFileRule+deriveJSON defaultOptions { fieldLabelModifier = mapHead lower . drop 3 } ''EnvSpec+deriveToJSON defaultOptions { fieldLabelModifier = mapHead lower . drop 3 } ''ConfigSpec+deriveToJSON defaultOptions { fieldLabelModifier = mapHead lower . drop 3 } ''MakeSpec +instance FromJSON SymlinkFileSpec where+  parseJSON = withObject "SymlinkSpec" $ \o -> do+    _slTarget <-   o .:  "target"+    _slLinkName <- o .: "linkName"+    _slPVPMajorLinks <- fromMaybe False <$> o .:? "pVPMajorLinks"+    _slSetName <- o .:? "setName"+    checkSafePath _slTarget+    checkSafeFilename _slLinkName+    forM_ _slSetName checkSafeFilename+    pure SymlinkSpec{..}++instance FromJSON SymlinkInputSpec where+  parseJSON = withObject "SymlinkInputSpec" $ \o -> do+    mTarget <- o .:?  "target"+    case mTarget of+      Just _slTarget -> do+        _slLinkName <- o .: "linkName"+        _slPVPMajorLinks <- o .:? "pVPMajorLinks" .!= False+        _slSetName <- o .:? "setName"+        checkSafePath _slTarget+        checkSafeFilename _slLinkName+        forM_ _slSetName checkSafeFilename+        pure SymlinkInputSpec{..}+      Nothing -> do+        _slTargetPattern <- o .: "targetPattern"+        _slTargetPatternIgnore <- o .:? "targetPatternIgnore" .!= []+        _slLinkName <- o .: "linkName"+        _slPVPMajorLinks <- o .:? "pVPMajorLinks" .!= False+        _slSetName <- o .:? "setName"+        forM_ _slTargetPattern checkSafePath+        forM_ _slTargetPatternIgnore checkSafePath+        checkSafeFilename _slLinkName+        forM_ _slSetName checkSafeFilename+        pure SymlinkPatternSpec{..}++instance FromJSON InstallFileRule where+  parseJSON = withObject "InstallFileRule" $ \o -> do+    installPattern   <- o .:? "installPattern"+    case installPattern of+      Just iPs -> do+        forM_ iPs checkSafePath+        pure $ InstallFilePatternRule iPs+      Nothing -> do+        installSource <- o .: "installSource"+        checkSafePath installSource+        installDest   <- o .:? "installDest"+        checkSafePath (fromMaybe "" installDest)+        pure $ InstallFileRule installSource installDest+++instance FromJSON ConfigSpec where+  parseJSON = withObject "ConfigSpec" $ \o -> do+    _csConfigArgs     <- o .:  "configArgs"+    _csConfigEnv      <- o .:? "configEnv"+    _csConfigFile     <- o .:? "configFile"++    pure $ ConfigSpec {..}++instance FromJSON MakeSpec where+  parseJSON = withObject "MakeSpec" $ \o -> do+    _msMakeArgs       <- o .:  "makeArgs"+    _msMakeEnv        <- o .:? "makeEnv"++    pure $ MakeSpec {..}++instance FromJSON a => FromJSON (InstallationSpecGen a) where+  parseJSON = withObject "InstallationSpec" $ \o -> do+    _isExeRules       <- o .:? "exeRules" .!= []+    _isDataRules      <- o .:? "dataRules" .!= []+    _isExeSymLinked   <- o .:? "exeSymLinked" .!= []+    _isConfigure      <- o .:? "configure"+    _isMake           <- o .:? "make"+    _isPreserveMtimes <- o .:? "preserveMtimes" .!= False++    pure $ InstallationSpec {..}++instance ToJSON a => ToJSON (InstallationSpecGen a) where+  toJSON = genericToJSON defaultOptions { fieldLabelModifier = mapHead lower . drop 3 }++ deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Requirements deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''DownloadInfo-deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''VersionInfo+deriveJSON defaultOptions { unwrapUnaryRecords = True } ''PlatformVersionSpec+deriveJSON defaultOptions { unwrapUnaryRecords = True } ''PlatformSpec+deriveJSON defaultOptions { unwrapUnaryRecords = True } ''ArchitectureSpec+deriveToJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''VersionInfo+deriveJSON defaultOptions { fieldLabelModifier = mapHead lower . drop 1 } ''ToolDescription +instance FromJSON InstallMetadata where+  parseJSON v = newParse v <|> legacyParse v+   where+    legacyParse o = do+      v'@DownloadInfo{..} <- parseJSON o+      case _dlInstallSpec of+        Nothing -> fail "No install metadata in legacy parser"+        Just InstallationSpec{..} -> do+          isExeSymLinked' <- forM _isExeSymLinked toSymlSpec+          pure $ InstallMetadata v' InstallationSpec{ _isExeSymLinked = isExeSymLinked', ..} Nothing 0++    toSymlSpec SymlinkInputSpec{..} = pure SymlinkSpec{..}+    toSymlSpec _ = fail "Can't handle SymlinkPatternSpec in legacy parser"++    newParse = do+      withObject "InstallMetadata" $ \o -> do+        _imDownloadInfo <- o .: "downloadInfo"+        _imResolvedInstallSpec <- o .: "resolvedInstallSpec"+        _imToolDescription <- o .:? "toolDescription"+        _imRevision <- o .:? "revision" .!= 0+        pure InstallMetadata{..}++instance FromJSON VersionInfo where+  parseJSON = withObject "VersionInfo" $ \o -> do+    _viSourceDL <- o .::? ["viSourceDL", "sourceDL"]+    _viTestDL <- o .::? ["viTestDL", "testDL"]+    _viArch <- o .:: ["viArch", "arch"]+    pure VersionInfo{..}++deriveJSON defaultOptions ''DhallRevision+deriveJSON defaultOptions { unwrapUnaryRecords = True } ''RevisionSpecDhall++instance FromJSON RevisionSpec where+  parseJSON v = newParse v <|> legacyParse v <|> dhallParse+   where+    legacyParse o = do+      vi <- parseJSON o+      pure $ RevisionSpec $ M.singleton (Rev 0) vi+    newParse o = do+      m <- parseJSON o+      pure $ RevisionSpec m+    dhallParse =+      (\(unRevisionSpecDhall -> dhallSpec) ->+        RevisionSpec $ M.fromList $ fmap (\DhallRevision{..} -> (Rev mapKey, mapValue)) dhallSpec+      )+      <$> parseJSON @RevisionSpecDhall v+++instance FromJSON VersionMetadata where+  parseJSON v = newParse v <|> legacyParse v+   where+    legacyParse =+      withObject "VersionMetadata" $ \o -> do+        _vmTags <- o .: "viTags"+        _vmReleaseDay <- o .:? "viReleaseDay"+        _vmChangeLog <- o .:? "viChangeLog"+        _viSourceDL <- o .:? "viSourceDL"+        _viTestDL <- o .:? "viTestDL"+        _viArch <- ArchitectureSpec <$> o .: "viArch"+        let vi = VersionInfo {..}+        let _vmRevisionSpec = RevisionSpec $ M.singleton (Rev 0) vi+        _vmPreInstall <- o .:? "viPreInstall"+        _vmPostInstall <- o .:? "viPostInstall"+        _vmPostRemove <- o .:? "viPostRemove"+        _vmPreCompile <- o .:? "viPreCompile"+        pure VersionMetadata{..}+    newParse = do+      withObject "VersionMetadata" $ \o -> do+        _vmTags         <- o .:? "tags" .!= []+        _vmReleaseDay   <- o .:? "releaseDay"+        _vmChangeLog    <- o .::? ["changelog", "changeLog"]+        _vmPreInstall   <- o .:? "preInstall"+        _vmPostInstall  <- o .:? "postInstall"+        _vmPostRemove   <- o .:? "postRemove"+        _vmPreCompile   <- o .:? "preCompile"+        _vmRevisionSpec <- o .:  "revisionSpec"+        pure VersionMetadata{..}++deriveToJSON defaultOptions { unwrapUnaryRecords = True } ''RevisionSpec++instance ToJSON VersionMetadata where+  toJSON VersionMetadata{..} = object+    [ "tags"         .= _vmTags+    , "releaseDay"   .= _vmReleaseDay+    , "changeLog"    .= _vmChangeLog+    , "preInstall"   .= _vmPreInstall+    , "postInstall"  .= _vmPostInstall+    , "postRemove"   .= _vmPostRemove+    , "preCompile"   .= _vmPreCompile+    , "revisionSpec" .= _vmRevisionSpec+    ]++deriveJSON defaultOptions { unwrapUnaryRecords = True } ''ToolVersionSpec+deriveToJSON defaultOptions { fieldLabelModifier = mapHead lower . drop 3 } ''InstallMetadata+deriveToJSON defaultOptions { fieldLabelModifier = mapHead lower . drop 1 } ''ToolInfo++instance FromJSON ToolInfo where+  parseJSON v = newParse v <|> legacyParse v+   where+    legacyParse o = do+      v' <- parseJSON o+      pure $ ToolInfo v' Nothing+    newParse = do+      withObject "ToolInfo" $ \o -> do+        _toolVersions <- o .: "toolVersions"+        _toolDetails <- o .: "toolDetails"+        pure ToolInfo{..}++deriveJSON defaultOptions { unwrapUnaryRecords = True } ''GHCupDownloads+ instance FromJSON GHCupInfo where   parseJSON = withObject "GHCupInfo" $ \o -> do-    toolRequirements' <- o .:? "toolRequirements"+    toolRequirements' <- o .:? "toolRequirements" .!= mempty     metadataUpdate    <- o .:? "metadataUpdate"     ghcupDownloads'   <- o .:  "ghcupDownloads"-    pure (GHCupInfo (fromMaybe mempty toolRequirements') ghcupDownloads' metadataUpdate)+    pure (GHCupInfo toolRequirements' ghcupDownloads' metadataUpdate)  deriveToJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''GHCupInfo  instance ToJSON NewURLSource where-  toJSON NewGHCupURL       = String "GHCupURL"-  toJSON NewStackSetupURL  = String "StackSetupURL"-  toJSON (NewGHCupInfo gi) = object [ "ghcup-info" .= gi ]-  toJSON (NewSetupInfo si) = object [ "setup-info" .= si ]-  toJSON (NewURI uri)      = toJSON uri+  toJSON NewGHCupURL         = String "GHCupURL"+  toJSON NewStackSetupURL    = String "StackSetupURL"+  toJSON (NewGHCupInfo gi)   = object [ "ghcup-info" .= gi ]+  toJSON (NewSetupInfo si)   = object [ "setup-info" .= si ]+  toJSON (NewURI uri)        = toJSON uri   toJSON (NewChannelAlias c) = toJSON c  instance ToJSON URLSource where@@ -323,7 +616,7 @@   parseJSON = withText "ChannelAlias" $ \t ->     let aliases = map (\c -> (channelAliasText c, c)) [minBound..maxBound]     in case lookup t aliases of-      Just c -> pure c+      Just c  -> pure c       Nothing -> fail $ "Unexpected ChannelAlias: " <> T.unpack t  deriveJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''Key@@ -335,6 +628,7 @@ deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''DownloadMirror deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''DownloadMirrors + instance FromJSON URLSource where   parseJSON v =         parseGHCupURL v@@ -358,7 +652,7 @@     <|> parseNewUrlSource' v    where     convert'' :: Either GHCupInfo URI -> Either (Either GHCupInfo SetupInfo) URI-    convert'' (Left gi)  = Left (Left gi)+    convert'' (Left gi)   = Left (Left gi)     convert'' (Right uri) = Right uri      parseOwnSourceLegacy = withObject "URLSource" $ \o -> do@@ -473,7 +767,16 @@        cmd  <- o .:? "cmd"        pure $ PagerConfig list cmd +instance FromJSON Verbosity where+  parseJSON v = new v <|> legacy v+   where+    legacy = withBool "Verbosity" $ \b -> do+      pure $ Verbosity (if b then 1 else 0)+    new = withScientific "Verbosity" $ \s -> do+      int <- maybe (fail "Verbosity integer out of bounds") pure $ toBoundedInteger s+      pure $ Verbosity int +deriveToJSON defaultOptions { unwrapUnaryRecords = True } ''Verbosity deriveToJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' T.unpack . T.stripPrefix (T.pack "pager-") . T.pack . kebab $ str' } ''PagerConfig deriveToJSON defaultOptions { fieldLabelModifier = drop 2 . kebab } ''KeyBindings -- move under key-bindings key deriveJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' T.unpack . T.stripPrefix (T.pack "k-") . T.pack . kebab $ str' } ''UserKeyBindings
lib/GHCup/Types/JSON/MapIgnoreUnknownKeys.hs view
@@ -1,19 +1,19 @@ {-# OPTIONS_GHC -Wno-orphans #-} -{-# LANGUAGE CPP                   #-}-{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE UndecidableInstances #-}  module GHCup.Types.JSON.MapIgnoreUnknownKeys where -import           GHCup.Types+import GHCup.Types -import           Data.Aeson              hiding (Key)-import           Data.Aeson.Types        hiding (Key)+import Data.Aeson       hiding ( Key )+import Data.Aeson.Types hiding ( Key ) -import qualified Data.Aeson.Key                as Key-import qualified Data.Aeson.KeyMap             as KeyMap-import qualified Data.Map.Strict               as Map+import qualified Data.Aeson.Key    as Key+import qualified Data.Aeson.KeyMap as KeyMap+import qualified Data.Map.Strict   as Map  #if defined(STRICT_METADATA_PARSING) -- | Use the instance of Map
lib/GHCup/Types/JSON/Utils.hs view
@@ -10,8 +10,22 @@  module GHCup.Types.JSON.Utils where -import qualified Data.Text                     as T+import Control.Applicative ( optional )+import Data.Aeson          ( FromJSON, Key, Object, (.:) )+import Data.Aeson.Types    ( Parser )+import Data.Foldable       ( asum )+import Data.Functor        ( (<&>) ) +import qualified Data.Text as T+ removeLensFieldLabel :: String -> String removeLensFieldLabel str' =   maybe str' T.unpack . T.stripPrefix (T.pack "_") . T.pack $ str'++(.::?) :: FromJSON a => Object -> [Key] -> Parser (Maybe a)+-- asum <$> traverse (o .:?) keys+(.::?) o keys = optional $ asum (keys <&> (o .:))++(.::) :: FromJSON a => Object -> [Key] -> Parser a+(.::) o keys = asum $ keys <&> (o .:)+
lib/GHCup/Types/JSON/Versions.hs view
@@ -1,10 +1,10 @@ {-# OPTIONS_GHC -Wno-orphans #-} -{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeFamilies #-}  {-| Module      : GHCup.Types.JSON.Versions@@ -17,11 +17,11 @@ -} module GHCup.Types.JSON.Versions where -import           Data.Aeson              hiding (Key)-import           Data.Aeson.Types        hiding (Key)-import           Data.Versions+import Data.Aeson       hiding ( Key )+import Data.Aeson.Types hiding ( Key )+import Data.Versions -import qualified Data.Text                     as T+import qualified Data.Text as T  instance ToJSON Versioning where   toJSON = toJSON . prettyV@@ -29,7 +29,7 @@ instance FromJSON Versioning where   parseJSON = withText "Versioning" $ \t -> case versioning t of     Right x -> pure x-    Left  e -> fail $ "Failure in GHCTargetVersion (FromJSON)" <> show e+    Left  e -> fail $ "Failure in TargetVersion (FromJSON)" <> show e  instance ToJSONKey Versioning where   toJSONKey = toJSONKeyText $ \x -> prettyV x
lib/GHCup/Types/Optics.hs view
@@ -1,12 +1,12 @@ {-# OPTIONS_GHC -Wno-orphans #-}-{-# LANGUAGE TemplateHaskell       #-}-{-# LANGUAGE ConstraintKinds       #-}-{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DuplicateRecordFields #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE AllowAmbiguousTypes   #-}-{-# LANGUAGE MultiParamTypeClasses   #-}-{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}  {-| Module      : GHCup.Types.Optics@@ -19,31 +19,61 @@ -} module GHCup.Types.Optics where -import           GHCup.Types+import GHCup.Types -import           Control.Monad.Reader-import           Data.ByteString         ( ByteString )-import           Optics-import           URI.ByteString+import Control.Monad.Reader+import Data.ByteString      ( ByteString )+import Data.Map.Strict      ( Map )+import Optics+import URI.ByteString +import qualified Data.Map.Strict as M + makePrisms ''Tool makePrisms ''Architecture makePrisms ''LinuxDistro makePrisms ''Platform makePrisms ''Tag+makePrisms ''EnvUnion+makePrisms ''GHCupDownloads+makePrisms ''ToolVersionSpec+makePrisms ''RevisionSpec+makePrisms ''ArchitectureSpec+makePrisms ''PlatformSpec+makePrisms ''PlatformVersionSpec+makePrisms ''Rev +makeLenses ''ToolInfo+makeLenses ''ToolDescription+makeLenses ''EnvSpec+makeLenses ''ConfigSpec+makeLenses ''MakeSpec+makeLenses ''InstallationSpecGen+makeLenses ''InstallMetadata makeLenses ''PlatformResult makeLenses ''DownloadInfo makeLenses ''Tag makeLenses ''VersionInfo+makeLenses ''VersionMetadata -makeLenses ''GHCTargetVersion+makeLenses ''TargetVersionReq+makeLenses ''TargetVersionRev+makeLenses ''InstallFileRule  makeLenses ''GHCupInfo  makeLenses ''CapturedProcess +toolVersionsL :: Lens' ToolInfo (Map TargetVersion VersionMetadata)+toolVersionsL = toolVersions % _ToolVersionSpec++revisionSpecL :: Getter VersionMetadata (Map Int VersionInfo)+revisionSpecL = vmRevisionSpec % _RevisionSpec % to (M.mapKeys unRev)++archL :: Lens' VersionInfo (MapIgnoreUnknownKeys Architecture PlatformSpec)+archL = viArch % _ArchitectureSpec+ uriSchemeL' :: Lens' (URIRef Absolute) Scheme uriSchemeL' = lensVL uriSchemeL @@ -71,8 +101,14 @@ queryL' :: Lens' (URIRef a) Query queryL' = lensVL queryL +mapLast :: AffineFold (Map k a) (k, a)+mapLast = to M.lookupMax % _Just +ixOrLast :: forall k v . Ord k => Maybe k -> AffineFold (Map k v) (k, v)+ixOrLast = maybe mapLast (\i -> castOptic @An_AffineFold (ix @(Map k v) i) % to (i,)) ++     ----------------------     --[ Lens utilities ]--     ----------------------@@ -88,18 +124,20 @@   getLeanAppState :: ( MonadReader env m-                   , LabelOptic' "settings"    A_Lens env Settings-                   , LabelOptic' "dirs"        A_Lens env Dirs-                   , LabelOptic' "keyBindings" A_Lens env KeyBindings+                   , LabelOptic' "settings"     A_Lens env Settings+                   , LabelOptic' "dirs"         A_Lens env Dirs+                   , LabelOptic' "keyBindings"  A_Lens env KeyBindings                    , LabelOptic' "loggerConfig" A_Lens env LoggerConfig+                   , LabelOptic' "pfreq"        A_Lens env PlatformRequest                    )                 => m LeanAppState getLeanAppState = do   s <- gets @"settings"   d <- gets @"dirs"   k <- gets @"keyBindings"+  p <- gets @"pfreq"   l <- gets @"loggerConfig"-  pure (LeanAppState s d k l)+  pure (LeanAppState s d k p l)   getSettings :: ( MonadReader env m@@ -161,4 +199,7 @@   instance LabelOptic "dirs" A_Lens Dirs Dirs Dirs Dirs where+  labelOptic = lens id (\_ d -> d)++instance LabelOptic "loggerConfig" A_Lens LoggerConfig LoggerConfig LoggerConfig LoggerConfig where   labelOptic = lens id (\_ d -> d)
lib/GHCup/Types/Stack.hs view
@@ -1,7 +1,11 @@ {-# OPTIONS_GHC -Wno-orphans #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE FlexibleInstances #-}+#if defined(DHALL)+{-# LANGUAGE DeriveAnyClass #-}+#endif  {-| Module      : GHCup.Types.Stack@@ -14,22 +18,57 @@ -} module GHCup.Types.Stack where -import           GHCup.Types.JSON.Versions ()+import GHCup.Types.JSON.Versions+    () -import           Control.Applicative-import           Control.DeepSeq                ( NFData )-import           Data.ByteString-import           Data.Aeson-import           Data.Aeson.Types-import           Data.Map.Strict                ( Map )-import           Data.Text                      ( Text )-import           Data.Text.Encoding-import           Data.Versions+import Control.Applicative+import Control.DeepSeq     ( NFData )+import Data.Aeson+import Data.Aeson.Types+import Data.ByteString+import Data.Map.Strict     ( Map )+import Data.Text.Encoding+import Data.Versions+#if defined(DHALL)+import Dhall+#else+import Data.Text ( Text )+#endif  import qualified Data.Map as Map-import qualified GHC.Generics                  as GHC+#if defined(DHALL)+import Data.Bifunctor ( first )+import Data.Void      ( Void )+import Dhall.Core     ( Expr )+import Dhall.Src      ( Src ) +import qualified Data.List.NonEmpty as NE+import qualified Data.Text          as T+import qualified Text.Megaparsec    as MP+#endif+import qualified GHC.Generics as GHC +++-- copy-pasted from GHCup.Types.Dhall++#if defined(DHALL)+instance FromDhall Version where+  autoWith _ =+    Dhall.string+      { extract = extractParser version'+      }++extractParser :: forall a. MP.Parsec Void T.Text a -> Expr Src Void -> Extractor Src Void a+extractParser parser = extractParser' (MP.parse parser "FromDhall")++extractParser' :: forall a e. Show e => (T.Text -> Either e a) -> Expr Src Void -> Extractor Src Void a+extractParser' parse' expr = fromMonadic $ do+  t <- toMonadic $ extract Dhall.string expr+  first (DhallErrors . NE.singleton . ExtractError . T.pack . show) . parse' . T.pack $ t+#endif++     --------------------------------------     --[ Stack download info copy pasta ]--     --------------------------------------@@ -37,11 +76,15 @@ data SetupInfo = SetupInfo   { siSevenzExe :: Maybe DownloadInfo   , siSevenzDll :: Maybe DownloadInfo-  , siMsys2     :: Map Text VersionedDownloadInfo-  , siGHCs      :: Map Text (Map Version GHCDownloadInfo)-  , siStack     :: Map Text (Map Version DownloadInfo)+  , siMsys2 :: Map Text VersionedDownloadInfo+  , siGHCs :: Map Text (Map Version GHCDownloadInfo)+  , siStack :: Map Text (Map Version DownloadInfo)   }-  deriving (Show, Eq, GHC.Generic)+  deriving (Eq, GHC.Generic, Show+#if defined(DHALL)+           , FromDhall+#endif+           )  instance NFData SetupInfo @@ -87,13 +130,17 @@ -- | Build of the compiler distribution (e.g. standard, gmp4, tinfo6) -- | Information for a file to download. data DownloadInfo = DownloadInfo-  { downloadInfoUrl           :: Text+  { downloadInfoUrl :: Text     -- ^ URL or absolute file path   , downloadInfoContentLength :: Maybe Int-  , downloadInfoSha1          :: Maybe ByteString-  , downloadInfoSha256        :: Maybe ByteString+  , downloadInfoSha1 :: Maybe ByteString+  , downloadInfoSha256 :: Maybe ByteString   }-  deriving (Show, Eq, GHC.Generic)+  deriving (Eq, GHC.Generic, Show+#if defined(DHALL)+           , FromDhall+#endif+           )  instance ToJSON DownloadInfo where   toJSON (DownloadInfo {..}) = object [ "url"            .= downloadInfoUrl@@ -123,10 +170,14 @@     }  data VersionedDownloadInfo = VersionedDownloadInfo-  { vdiVersion      :: Version+  { vdiVersion :: Version   , vdiDownloadInfo :: DownloadInfo   }-  deriving (Show, Eq, GHC.Generic)+  deriving (Eq, GHC.Generic, Show+#if defined(DHALL)+           , FromDhall+#endif+           )  instance ToJSON VersionedDownloadInfo where   toJSON (VersionedDownloadInfo {vdiDownloadInfo = DownloadInfo{..}, ..})@@ -150,10 +201,14 @@  data GHCDownloadInfo = GHCDownloadInfo   { gdiConfigureOpts :: [Text]-  , gdiConfigureEnv  :: Map Text Text-  , gdiDownloadInfo  :: DownloadInfo+  , gdiConfigureEnv :: Map Text Text+  , gdiDownloadInfo :: DownloadInfo   }-  deriving (Show, Eq, GHC.Generic)+  deriving (Eq, GHC.Generic, Show+#if defined(DHALL)+           , FromDhall+#endif+           )  instance NFData GHCDownloadInfo 
+ lib/GHCup/Types/Tar.hs view
@@ -0,0 +1,33 @@+{-# LANGUAGE CPP #-}+#if defined(TAR)+{-# LANGUAGE DeriveGeneric #-}+#endif++module GHCup.Types.Tar+  ( ArchiveResult(..)+  )+  where++#if defined(TAR)++import           Control.Exception              ( Exception )+import           Control.DeepSeq                ( NFData )+import qualified GHC.Generics                   as GHC++data ArchiveResult = ArchiveFatal+                   | ArchiveFailed+                   | ArchiveWarn+                   | ArchiveRetry+                   | ArchiveOk+                   | ArchiveEOF+  deriving (Eq, Show, GHC.Generic)++instance NFData ArchiveResult++instance Exception ArchiveResult++#else++import           Codec.Archive                  ( ArchiveResult(..) )++#endif
+ lib/GHCup/Unpack.hs view
@@ -0,0 +1,140 @@+{-# LANGUAGE CPP                   #-}+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE OverloadedStrings     #-}++{-|+Module      : GHCup.Unpack+Description : GHCup tar abstractions+Copyright   : (c) Julian Ospald, 2024+License     : LGPL-3.0+Maintainer  : hasufell@hasufell.de+Stability   : experimental+Portability : portable+-}+module GHCup.Unpack where++import           GHCup.Types.Tar ( ArchiveResult(..) )+import           GHCup.Errors+import           GHCup.Prelude+import           GHCup.Types.Optics++import           Control.Monad.Catch (MonadThrow)+import           Control.Monad.Reader+import           Data.List+import           Data.Variant.Excepts+import           System.FilePath++#if defined(TAR)+import           Codec.Archive.Zip+import qualified Codec.Archive.Tar             as Tar+import qualified Codec.Archive.Tar.Entry       as Tar+import qualified Data.Map.Strict               as Map+#else+import           Codec.Archive           hiding ( Directory+                                                , ArchiveResult -- imported from "GHCup.Unpack"+                                                )+#endif++import qualified Codec.Compression.BZip        as BZip+import qualified Codec.Compression.GZip        as GZip+import qualified Codec.Compression.Lzma        as Lzma+import qualified Data.ByteString.Lazy          as BL+import qualified Data.Text                     as T+++-- | Unpack an archive to a given directory.+unpackToDir :: (MonadReader env m, HasLog env, MonadIO m, MonadThrow m)+            => FilePath       -- ^ destination dir+            -> FilePath       -- ^ archive path+            -> Excepts '[UnknownArchive+                        , ArchiveResult+                        ] m ()+unpackToDir dfp av = do+  let fn = takeFileName av+  lift $ logInfo $ "Unpacking: " <> T.pack fn <> " to " <> T.pack dfp++#if defined(TAR)+  let untar :: MonadIO m => BL.ByteString -> Excepts '[ArchiveResult] m ()+      untar = liftIO . Tar.unpack dfp . Tar.read++      rf :: MonadIO m => FilePath -> Excepts '[ArchiveResult] m BL.ByteString+      rf = liftIO . BL.readFile+#else+  let untar :: MonadIO m => BL.ByteString -> Excepts '[ArchiveResult] m ()+      untar = lEM . liftIO . runArchiveM . unpackToDirLazy dfp++      rf :: MonadIO m => FilePath -> Excepts '[ArchiveResult] m BL.ByteString+      rf = liftIO . BL.readFile+#endif++  -- extract, depending on file extension+  if+    | ".tar.gz" `isSuffixOf` fn -> liftE+      (untar . GZip.decompress =<< rf av)+    | ".tar.xz" `isSuffixOf` fn -> do+      filecontents <- liftE $ rf av+      let decompressed = Lzma.decompressWith (Lzma.defaultDecompressParams { Lzma.decompressAutoDecoder= True }) filecontents+      liftE $ untar decompressed+    | ".tar.bz2" `isSuffixOf` fn ->+      liftE (untar . BZip.decompress =<< rf av)+    | ".tar" `isSuffixOf` fn -> liftE (untar =<< rf av)+#if defined(TAR)+    | ".zip" `isSuffixOf` fn -> withArchive av (unpackInto dfp)+#else+    -- libarchive supports zip+    | ".zip" `isSuffixOf` fn -> liftE (untar =<< rf av)+#endif+    | otherwise -> throwE $ UnknownArchive fn+++-- | Get all files from an archive.+getArchiveFiles :: (MonadIO m, MonadThrow m)+                => FilePath       -- ^ archive path+                -> Excepts '[ UnknownArchive+                            , ArchiveResult+                            ] m [FilePath]+getArchiveFiles av = do+  let fn = takeFileName av+#if defined(TAR)+  let entries :: Monad m => BL.ByteString -> Excepts '[ArchiveResult] m [FilePath]+      entries =+          lE @ArchiveResult+          . Tar.foldEntries+            (\e x -> fmap (Tar.entryTarPath e :) x)+            (Right [])+            (\_ -> Left ArchiveFailed)+          . Tar.decodeLongNames+          . Tar.read++      rf :: MonadIO m => FilePath -> Excepts '[ArchiveResult] m BL.ByteString+      rf = liftIO . BL.readFile+#else+  let entries :: Monad m => BL.ByteString -> Excepts '[ArchiveResult] m [FilePath]+      entries = (fmap . fmap) filepath . lE . readArchiveBSL++      rf :: MonadIO m => FilePath -> Excepts '[ArchiveResult] m BL.ByteString+      rf = liftIO . BL.readFile+#endif++  -- extract, depending on file extension+  if+    | ".tar.gz" `isSuffixOf` fn -> liftE+      (entries . GZip.decompress =<< rf av)+    | ".tar.xz" `isSuffixOf` fn -> do+      filecontents <- liftE $ rf av+      let decompressed = Lzma.decompressWith (Lzma.defaultDecompressParams { Lzma.decompressAutoDecoder= True }) filecontents+      liftE $ entries decompressed+    | ".tar.bz2" `isSuffixOf` fn ->+      liftE (entries . BZip.decompress =<< rf av)+    | ".tar" `isSuffixOf` fn -> liftE (entries =<< rf av)+    | ".zip" `isSuffixOf` fn ->+#if defined(TAR)+        withArchive av $ do+          entries' <- getEntries+          pure $ fmap unEntrySelector $ Map.keys entries'+#else+        liftE (entries =<< rf av)+#endif+    | otherwise -> throwE $ UnknownArchive fn+
− lib/GHCup/Utils.hs
@@ -1,1272 +0,0 @@-{-# LANGUAGE CPP                   #-}-{-# LANGUAGE BangPatterns          #-}-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE QuasiQuotes           #-}-{-# LANGUAGE TypeApplications      #-}-{-# LANGUAGE ViewPatterns          #-}--{-|-Module      : GHCup.Utils-Description : GHCup domain specific utilities-Copyright   : (c) Julian Ospald, 2020-License     : LGPL-3.0-Maintainer  : hasufell@hasufell.de-Stability   : experimental-Portability : portable--This module contains GHCup helpers specific to-installation and introspection of files/versions etc.--}-module GHCup.Utils-  ( module GHCup.Utils.Dirs-  , module GHCup.Utils.Tar-  , module GHCup.Utils-  , module GHCup.Utils.URI-#if defined(IS_WINDOWS)-  , module GHCup.Prelude.Windows-#else-  , module GHCup.Prelude.Posix-#endif-  )-where---#if defined(IS_WINDOWS)-import GHCup.Prelude.Windows-#else-import GHCup.Prelude.Posix-#endif-import           GHCup.Download-import           GHCup.Errors-import           GHCup.Types-import           GHCup.Types.Optics-import           GHCup.Types.JSON               ( )-import           GHCup.Utils.Dirs-import           GHCup.Utils.Tar-import           GHCup.Utils.URI-import           GHCup.Version-import           GHCup.Prelude-import           GHCup.Prelude.File-import           GHCup.Prelude.Logger.Internal-import           GHCup.Prelude.MegaParsec-import           GHCup.Prelude.Process-import           GHCup.Prelude.String.QQ-import           Control.Applicative-import           Control.Exception.Safe-import           Control.Monad-#if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )-#endif-import           Conduit ((.|), runConduitRes)-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-                                         hiding ( throwM )-import           Control.Monad.IO.Unlift        ( MonadUnliftIO( withRunInIO ) )-import           Data.Char                      ( isHexDigit )-import           Data.ByteString                ( ByteString )-import           Data.Either-import           Data.Foldable-import           Data.List                      ( sort, stripPrefix, isPrefixOf, nub, isInfixOf, isSuffixOf, groupBy, sortBy )-import           Data.List.NonEmpty             ( NonEmpty( (:|) ))-import           Data.Maybe-import           Data.Text                      ( Text )-import           Data.Versions         hiding   ( patch )-import           GHC.IO.Exception-import           Data.Variant.Excepts-import           Optics-import           Safe-import           System.FilePath-import           System.IO.Error-import           Text.Regex.Posix-import           Text.PrettyPrint.HughesPJClass (prettyShow)-import           URI.ByteString hiding (parseURI)--import qualified Data.Map.Strict               as Map-import qualified Data.Text                     as T-import qualified Data.Text.Encoding            as E-import qualified Text.Megaparsec               as MP-import qualified Data.List.NonEmpty            as NE-import qualified Data.Conduit.Combinators as C--import Control.DeepSeq (force)-import GHC.IO (evaluate)-import Data.Time (Day(..), diffDays, addDays)----- $setup--- >>> :set -XOverloadedStrings--- >>> :set -XDataKinds--- >>> :set -XTypeApplications--- >>> :set -XQuasiQuotes--- >>> import System.Directory--- >>> import URI.ByteString--- >>> import qualified Data.Text as T--- >>> import GHCup.Prelude--- >>> import GHCup.Download--- >>> import GHCup.Version--- >>> import GHCup.Errors--- >>> import GHCup.Types--- >>> import GHCup.Types.Optics--- >>> import Data.Versions--- >>> import Optics--- >>> import GHCup.Prelude.Version.QQ--- >>> import qualified Data.Text.Encoding as E--- >>> import Control.Monad.Reader--- >>> import Data.Variant.Excepts--- >>> import Text.PrettyPrint.HughesPJClass ( prettyShow )--- >>> let lc = LoggerConfig { lcPrintDebug = False, consoleOutter = mempty, fileOutter = mempty, fancyColors = False }--- >>> dirs' <- getAllDirs--- >>> let installedVersions = [ ([pver|8.10.7|], "-debug+lol", Nothing), ([pver|8.10.4|], "", Nothing), ([pver|8.8.4|], "", Nothing), ([pver|8.8.3|], "", Nothing) ]--- >>> let settings = defaultSettings { cache = True, metaCache = 0, noNetwork = True }--- >>> let leanAppState = LeanAppState settings dirs' defaultKeyBindings lc--- >>> cwd <- getCurrentDirectory--- >>> (Right ref) <- pure $ GHCup.Utils.parseURI $ "file://" <> E.encodeUtf8 (T.pack cwd) <> "/data/metadata/" <> (urlBaseName . view pathL' $ ghcupURL)--- >>> (VRight r) <- (fmap . fmap) _ghcupDownloads $ flip runReaderT leanAppState . runE @'[DigestError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError, ContentLengthError] $ liftE (getBase ref) >>= liftE . decodeMetadata @GHCupInfo----    -------------------------    --[ Symlink handling ]---    ----------------------------- | Create a relative symlink destination for the binary directory,--- given a target toolpath.-binarySymLinkDestination :: ( MonadThrow m-                            , MonadIO m-                            )-                         => FilePath -- ^ binary dir-                         -> FilePath -- ^ the full toolpath-                         -> m FilePath-binarySymLinkDestination binDir toolPath = do-  toolPath' <- liftIO $ canonicalizePath toolPath-  binDir' <- liftIO $ canonicalizePath binDir-  pure (relativeSymlink binDir' toolPath')----- | Removes the minor GHC symlinks, e.g. ghc-8.6.5.-rmMinorGHCSymlinks :: ( MonadReader env m-                      , HasDirs env-                      , MonadIO m-                      , HasLog env-                      , MonadThrow m-                      , MonadFail m-                      , MonadMask m-                      )-                   => GHCTargetVersion-                   -> Excepts '[NotInstalled] m ()-rmMinorGHCSymlinks tv@GHCTargetVersion{..} = do-  Dirs {..}  <- lift getDirs--  files                         <- liftE $ ghcToolFiles tv-  forM_ files $ \f -> do-    let f_xyz = f <> "-" <> T.unpack (prettyVer _tvVersion) <> exeExt-    let fullF = binDir </> f_xyz-    lift $ logDebug ("rm -f " <> T.pack fullF)-    lift $ hideError doesNotExistErrorType $ rmLink fullF----- | Removes the set ghc version for the given target, if any.-rmPlainGHC :: ( MonadReader env m-              , HasDirs env-              , HasLog env-              , MonadThrow m-              , MonadFail m-              , MonadIO m-              , MonadMask m-              )-           => Maybe Text -- ^ target-           -> Excepts '[NotInstalled] m ()-rmPlainGHC target = do-  Dirs {..}  <- lift getDirs-  mtv                           <- lift $ ghcSet target-  forM_ mtv $ \tv -> do-    files <- liftE $ ghcToolFiles tv-    forM_ files $ \f -> do-      let fullF = binDir </> f <> exeExt-      lift $ logDebug ("rm -f " <> T.pack fullF)-      lift $ hideError doesNotExistErrorType $ rmLink fullF-    -- old ghcup-    let hdc_file = binDir </> "haddock-ghc" <> exeExt-    lift $ logDebug ("rm -f " <> T.pack hdc_file)-    lift $ hideError doesNotExistErrorType $ rmLink hdc_file----- | Remove the major GHC symlink, e.g. ghc-8.6.-rmMajorGHCSymlinks :: ( MonadReader env m-                      , HasDirs env-                      , MonadIO m-                      , HasLog env-                      , MonadThrow m-                      , MonadFail m-                      , MonadMask m-                      )-                   => GHCTargetVersion-                   -> Excepts '[NotInstalled] m ()-rmMajorGHCSymlinks tv@GHCTargetVersion{..} = do-  Dirs {..}  <- lift getDirs-  (mj, mi) <- getMajorMinorV _tvVersion-  let v' = intToText mj <> "." <> intToText mi--  files                         <- liftE $ ghcToolFiles tv-  forM_ files $ \f -> do-    let f_xy = f <> "-" <> T.unpack v' <> exeExt-    let fullF = binDir </> f_xy-    lift $ logDebug ("rm -f " <> T.pack fullF)-    lift $ hideError doesNotExistErrorType $ rmLink fullF----- | Removes the minor HLS files, e.g. 'haskell-language-server-8.10.7~1.6.1.0'--- and 'haskell-language-server-wrapper-1.6.1.0'.-rmMinorHLSSymlinks :: ( MonadReader env m-                      , HasDirs env-                      , MonadIO m-                      , HasLog env-                      , MonadThrow m-                      , MonadFail m-                      , MonadMask m-                      )-                   => Version-                   -> Excepts '[NotInstalled] m ()-rmMinorHLSSymlinks ver = do-  Dirs {..}  <- lift getDirs--  hlsBins <- hlsAllBinaries ver-  forM_ hlsBins $ \f -> do-    let fullF = binDir </> f-    lift $ logDebug ("rm -f " <> T.pack fullF)-    -- on unix, this may be either a file (legacy) or a symlink-    -- on windows, this is always a file... hence 'rmFile'-    -- works consistently across platforms-    lift $ rmFile fullF---- | Removes the set HLS version, if any.-rmPlainHLS :: ( MonadReader env m-              , HasDirs env-              , HasLog env-              , MonadThrow m-              , MonadFail m-              , MonadIO m-              , MonadMask m-              )-           => Excepts '[NotInstalled] m ()-rmPlainHLS = do-  Dirs {..}  <- lift getDirs--  -- delete 'haskell-language-server-8.10.7'-  hlsBins <- fmap (filter (\f -> not ("haskell-language-server-wrapper" `isPrefixOf` f) && ('~' `notElem` f)))-    $ liftIO $ handleIO (\_ -> pure []) $ findFiles-      binDir-      (makeRegexOpts compExtended execBlank ([s|^haskell-language-server-.*$|] :: ByteString))-  forM_ hlsBins $ \f -> do-    let fullF = binDir </> f-    lift $ logDebug ("rm -f " <> T.pack fullF)-    if isWindows-    then lift $ rmLink fullF-    else lift $ rmFile fullF--  -- 'haskell-language-server-wrapper'-  let hlswrapper = binDir </> "haskell-language-server-wrapper" <> exeExt-  lift $ logDebug ("rm -f " <> T.pack hlswrapper)-  if isWindows-  then lift $ hideError doesNotExistErrorType $ rmLink hlswrapper-  else lift $ hideError doesNotExistErrorType $ rmFile hlswrapper----    ------------------------------------    --[ Set/Installed introspection ]---    ---------------------------------------- | Whether the given GHC version is installed.-ghcInstalled :: (MonadIO m, MonadReader env m, HasDirs env, MonadThrow m) => GHCTargetVersion -> m Bool-ghcInstalled ver = do-  ghcdir <- ghcupGHCDir ver-  liftIO $ doesDirectoryExist (fromGHCupPath ghcdir)----- | Whether the given GHC version is set as the current.-ghcSet :: (MonadReader env m, HasDirs env, MonadThrow m, MonadIO m)-       => Maybe Text   -- ^ the target of the GHC version, if any-                       --  (e.g. armv7-unknown-linux-gnueabihf)-       -> m (Maybe GHCTargetVersion)-ghcSet mtarget = do-  Dirs {..}  <- getDirs-  let ghc = maybe "ghc" (\t -> T.unpack t <> "-ghc") mtarget-  let ghcBin = binDir </> ghc <> exeExt--  -- link destination is of the form ../ghc/<ver>/bin/ghc-  -- for old ghcup, it is ../ghc/<ver>/bin/ghc-<ver>-  liftIO $ handleIO' NoSuchThing (\_ -> pure Nothing) $ do-    link <- liftIO $ getLinkTarget ghcBin-    Just <$> ghcLinkVersion link- where-  ghcLinkVersion :: MonadThrow m => FilePath -> m GHCTargetVersion-  ghcLinkVersion (T.pack . dropSuffix exeExt -> t) = throwEither $ MP.parse ghcVersionFromPath "ghcLinkVersion" t---- | Get all installed GHCs by reading ~/.ghcup/ghc/<dir>.--- If a dir cannot be parsed, returns left.-getInstalledGHCs :: (MonadReader env m, HasDirs env, MonadIO m) => m [Either FilePath GHCTargetVersion]-getInstalledGHCs = do-  ghcdir <- ghcupGHCBaseDir-  fs     <- liftIO $ hideErrorDef [NoSuchThing] [] $ listDirectoryDirs (fromGHCupPath ghcdir)-  forM fs $ \f -> case parseGHCupGHCDir f of-    Right r -> pure $ Right r-    Left  _ -> pure $ Left f----- | Get all installed cabals, by matching on @~\/.ghcup\/bin/cabal-*@.-getInstalledCabals :: ( MonadReader env m-                      , HasDirs env-                      , MonadIO m-                      , MonadCatch m-                      )-                   => m [Either FilePath Version]-getInstalledCabals = do-  Dirs {..} <- getDirs-  bins   <- liftIO $ handleIO (\_ -> pure []) $ findFiles-    binDir-    (makeRegexOpts compExtended execBlank ([s|^cabal-.*$|] :: ByteString))-  vs <- forM bins $ \f -> case version . T.pack <$> (stripSuffix exeExt =<< stripPrefix "cabal-" f) of-    Just (Right r) -> pure $ Right r-    Just (Left  _) -> pure $ Left f-    Nothing        -> pure $ Left f-  pure $ nub vs----- | Whether the given cabal version is installed.-cabalInstalled :: (MonadIO m, MonadReader env m, HasDirs env, MonadCatch m) => Version -> m Bool-cabalInstalled ver = do-  vers <- fmap rights getInstalledCabals-  pure $ elem ver vers----- Return the currently set cabal version, if any.-cabalSet :: (HasLog env, MonadReader env m, HasDirs env, MonadIO m, MonadThrow m, MonadCatch m) => m (Maybe Version)-cabalSet = do-  Dirs {..}  <- getDirs-  let cabalbin = binDir </> "cabal" <> exeExt--  handleIO' NoSuchThing (\_ -> pure Nothing) $ do-    broken <- liftIO $ isBrokenSymlink cabalbin-    if broken-      then do-        logWarn $ "Broken symlink at " <> T.pack cabalbin-        pure Nothing-      else do-        link <- liftIO-          $ handleIO' InvalidArgument-            (\e -> pure $ Left (toException e))-          $ fmap Right $ getLinkTarget cabalbin-        case linkVersion =<< link of-          Right v -> pure $ Just v-          Left err -> do-            logWarn $ "Failed to parse cabal symlink target with: "-              <> T.pack (displayException err)-              <> ". The symlink "-              <> T.pack cabalbin-              <> " needs to point to valid cabal binary, such as 'cabal-3.4.0.0'."-            pure Nothing- where-  -- We try to be extra permissive with link destination parsing,-  -- because of:-  --   https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/119-  linkVersion :: MonadThrow m => FilePath -> m Version-  linkVersion = throwEither . MP.parse parser "linkVersion" . T.pack . dropSuffix exeExt--  parser-    =   MP.try (stripAbsolutePath *> cabalParse)-    <|> MP.try (stripRelativePath *> cabalParse)-    <|> cabalParse-  -- parses the version of "cabal-3.2.0.0" -> "3.2.0.0"-  cabalParse = MP.chunk "cabal-" *> version'-  -- parses any path component ending with path separator,-  -- e.g. "foo/"-  stripPathComponet = parseUntil1 pathSep *> MP.some pathSep-  -- parses an absolute path up until the last path separator,-  -- e.g. "/bar/baz/foo" -> "/bar/baz/", leaving "foo"-  stripAbsolutePath = MP.some pathSep *> MP.many (MP.try stripPathComponet)-  -- parses a relative path up until the last path separator,-  -- e.g. "bar/baz/foo" -> "bar/baz/", leaving "foo"-  stripRelativePath = MP.many (MP.try stripPathComponet)------ | Get all installed hls, by matching on--- @~\/.ghcup\/bin/haskell-language-server-wrapper-<\hlsver\>@,--- as well as @~\/.ghcup\/hls\/<\hlsver\>@-getInstalledHLSs :: (MonadReader env m, HasDirs env, MonadIO m, MonadCatch m)-                 => m [Either FilePath Version]-getInstalledHLSs = do-  Dirs {..}  <- getDirs-  bins                          <- liftIO $ handleIO (\_ -> pure []) $ findFiles-    binDir-    (makeRegexOpts compExtended-                   execBlank-                   ([s|^haskell-language-server-wrapper-.*$|] :: ByteString)-    )-  legacy <- forM bins $ \f ->-    case-          version . T.pack <$> (stripSuffix exeExt =<< stripPrefix "haskell-language-server-wrapper-" f)-      of-        Just (Right r) -> pure $ Right r-        Just (Left  _) -> pure $ Left f-        Nothing        -> pure $ Left f--  hlsdir <- ghcupHLSBaseDir-  fs     <- liftIO $ hideErrorDef [NoSuchThing] [] $ listDirectoryDirs (fromGHCupPath hlsdir)-  new <- forM fs $ \f -> case parseGHCupHLSDir f of-    Right r -> pure $ Right r-    Left  _ -> pure $ Left f-  pure (nub (new <> legacy))----- | Get all installed stacks, by matching on--- @~\/.ghcup\/bin/stack-<\stackver\>@.-getInstalledStacks :: (MonadReader env m, HasDirs env, MonadIO m, MonadCatch m)-                   => m [Either FilePath Version]-getInstalledStacks = do-  Dirs {..}  <- getDirs-  bins                          <- liftIO $ handleIO (\_ -> pure []) $ findFiles-    binDir-    (makeRegexOpts compExtended-                   execBlank-                   ([s|^stack-.*$|] :: ByteString)-    )-  forM bins $ \f ->-    case version . T.pack <$> (stripSuffix exeExt =<< stripPrefix "stack-" f) of-        Just (Right r) -> pure $ Right r-        Just (Left  _) -> pure $ Left f-        Nothing        -> pure $ Left f---- Return the currently set stack version, if any.--- TODO: there's a lot of code duplication here :>-stackSet :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m, MonadCatch m, HasLog env) => m (Maybe Version)-stackSet = do-  Dirs {..}  <- getDirs-  let stackBin = binDir </> "stack" <> exeExt--  handleIO' NoSuchThing (\_ -> pure Nothing) $ do-    broken <- liftIO $ isBrokenSymlink stackBin-    if broken-      then do-        logWarn $ "Broken symlink at " <> T.pack stackBin-        pure Nothing-      else do-        link <- liftIO-          $ handleIO' InvalidArgument-            (\e -> pure $ Left (toException e))-          $ fmap Right $ getLinkTarget stackBin-        case linkVersion =<< link of-          Right v -> pure $ Just v-          Left err -> do-            logWarn $ "Failed to parse stack symlink target with: "-              <> T.pack (displayException err)-              <> ". The symlink "-              <> T.pack stackBin-              <> " needs to point to valid stack binary, such as 'stack-2.7.1'."-            pure Nothing- where-  linkVersion :: MonadThrow m => FilePath -> m Version-  linkVersion = throwEither . MP.parse parser "" . T.pack . dropSuffix exeExt-   where-    parser-      =   MP.try (stripAbsolutePath *> cabalParse)-      <|> MP.try (stripRelativePath *> cabalParse)-      <|> cabalParse-    -- parses the version of "stack-2.7.1" -> "2.7.1"-    cabalParse = MP.chunk "stack-" *> version'-    -- parses any path component ending with path separator,-    -- e.g. "foo/"-    stripPathComponet = parseUntil1 pathSep *> MP.some pathSep-    -- parses an absolute path up until the last path separator,-    -- e.g. "/bar/baz/foo" -> "/bar/baz/", leaving "foo"-    stripAbsolutePath = MP.some pathSep *> MP.many (MP.try stripPathComponet)-    -- parses a relative path up until the last path separator,-    -- e.g. "bar/baz/foo" -> "bar/baz/", leaving "foo"-    stripRelativePath = MP.many (MP.try stripPathComponet)---- | Whether the given Stack version is installed.-stackInstalled :: (MonadIO m, MonadReader env m, HasDirs env, MonadCatch m) => Version -> m Bool-stackInstalled ver = do-  vers <- fmap rights getInstalledStacks-  pure $ elem ver vers---- | Whether the given HLS version is installed.-hlsInstalled :: (MonadIO m, MonadReader env m, HasDirs env, MonadCatch m) => Version -> m Bool-hlsInstalled ver = do-  vers <- fmap rights getInstalledHLSs-  pure $ elem ver vers--isLegacyHLS :: (MonadIO m, MonadReader env m, HasDirs env, MonadCatch m) => Version -> m Bool-isLegacyHLS ver = do-  bdir <- ghcupHLSDir ver-  not <$> liftIO (doesDirectoryExist $ fromGHCupPath bdir)----- Return the currently set hls version, if any.-hlsSet :: (HasLog env, MonadReader env m, HasDirs env, MonadIO m, MonadThrow m, MonadCatch m) => m (Maybe Version)-hlsSet = do-  Dirs {..}  <- getDirs-  let hlsBin = binDir </> "haskell-language-server-wrapper" <> exeExt--  handleIO' NoSuchThing (\_ -> pure Nothing) $ do-    broken <- liftIO $ isBrokenSymlink hlsBin-    if broken-      then do-        logWarn $ "Broken symlink at " <> T.pack hlsBin-        pure Nothing-      else do-        link <- liftIO $ getLinkTarget hlsBin-        Just <$> linkVersion link- where-  linkVersion :: MonadThrow m => FilePath -> m Version-  linkVersion = throwEither . MP.parse parser "" . T.pack . dropSuffix exeExt-   where-    parser-      =   MP.try (stripAbsolutePath *> cabalParse)-      <|> MP.try (stripRelativePath *> cabalParse)-      <|> cabalParse-    -- parses the version of "haskell-language-server-wrapper-1.1.0" -> "1.1.0"-    cabalParse = MP.chunk "haskell-language-server-wrapper-" *> version'-    -- parses any path component ending with path separator,-    -- e.g. "foo/"-    stripPathComponet = parseUntil1 pathSep *> MP.some pathSep-    -- parses an absolute path up until the last path separator,-    -- e.g. "/bar/baz/foo" -> "/bar/baz/", leaving "foo"-    stripAbsolutePath = MP.some pathSep *> MP.many (MP.try stripPathComponet)-    -- parses a relative path up until the last path separator,-    -- e.g. "bar/baz/foo" -> "bar/baz/", leaving "foo"-    stripRelativePath = MP.many (MP.try stripPathComponet)----- | Return the GHC versions the currently selected HLS supports.-hlsGHCVersions :: ( MonadReader env m-                  , HasDirs env-                  , HasLog env-                  , MonadIO m-                  , MonadThrow m-                  , MonadCatch m-                  )-               => m [Version]-hlsGHCVersions = do-  h <- hlsSet-  fromMaybe [] <$> forM h hlsGHCVersions'---hlsGHCVersions' :: ( MonadReader env m-                   , HasDirs env-                   , MonadIO m-                   , MonadThrow m-                   , MonadCatch m-                   )-                => Version-                -> m [Version]-hlsGHCVersions' v' = do-  bins <- hlsServerBinaries v' Nothing-  let vers = fmap-        (version-          . T.pack-          . fromJust-          . stripPrefix "haskell-language-server-"-          . head-          . splitOn "~"-          )-        bins-  pure . sortBy (flip compare) . rights $ vers----- | Get all server binaries for an hls version from the ~/.ghcup/bin directory, if any.-hlsServerBinaries :: (MonadReader env m, HasDirs env, MonadIO m)-                  => Version-                  -> Maybe Version   -- ^ optional GHC version-                  -> m [FilePath]-hlsServerBinaries ver mghcVer = do-  Dirs {..}  <- getDirs-  liftIO $ handleIO (\_ -> pure []) $ findFiles-    binDir-    (makeRegexOpts-      compExtended-      execBlank-      ([s|^haskell-language-server-|]-        <> maybe [s|.*|] escapeVerRex mghcVer-        <> [s|~|]-        <> escapeVerRex ver-        <> E.encodeUtf8 (T.pack exeExt)-        <> [s|$|] :: ByteString-      )-    )---- | Get all scripts for a hls version from the ~/.ghcup/hls/<ver>/bin directory, if any.--- Returns the full path.-hlsInternalServerScripts :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m)-                          => Version-                          -> Maybe Version   -- ^ optional GHC version-                          -> m [FilePath]-hlsInternalServerScripts ver mghcVer = do-  dir <- ghcupHLSDir ver-  let bdir = fromGHCupPath dir </> "bin"-  fmap (bdir </>) . filter (\f -> maybe True (\gv -> ("-" <> T.unpack (prettyVer gv)) `isSuffixOf` f) mghcVer)-    <$> liftIO (listDirectoryFiles bdir)---- | Get all binaries for a hls version from the ~/.ghcup/hls/<ver>/lib/haskell-language-server-<ver>/bin directory, if any.--- Returns the full path.-hlsInternalServerBinaries :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m, MonadFail m)-                          => Version-                          -> Maybe Version   -- ^ optional GHC version-                          -> m [FilePath]-hlsInternalServerBinaries ver mghcVer = do-  dir <- fromGHCupPath <$> ghcupHLSDir ver-  let regex = makeRegexOpts compExtended execBlank ([s|^haskell-language-server-.*$|] :: ByteString)-  (Just bdir) <- fmap headMay $ liftIO $ expandFilePath [Left (dir </> "lib"), Right regex, Left "bin"]-  fmap (bdir </>) . filter (\f -> maybe True (\gv -> ("-" <> T.unpack (prettyVer gv)) `isSuffixOf` f) mghcVer)-    <$> liftIO (listDirectoryFiles bdir)---- | Get all libraries for a hls version from the ~/.ghcup/hls/<ver>/lib/haskell-language-server-<ver>/lib/<ghc-ver>/--- directory, if any.--- Returns the full path.-hlsInternalServerLibs :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m, MonadFail m)-                      => Version-                      -> Version   -- ^ GHC version-                      -> m [FilePath]-hlsInternalServerLibs ver ghcVer = do-  dir <- fromGHCupPath <$> ghcupHLSDir ver-  let regex = makeRegexOpts compExtended execBlank ([s|^haskell-language-server-.*$|] :: ByteString)-  (Just bdir) <- fmap headMay $ liftIO $ expandFilePath [Left (dir </> "lib"), Right regex, Left ("lib" </> T.unpack (prettyVer ghcVer))]-  fmap (bdir </>) <$> liftIO (listDirectoryFiles bdir)----- | Get the wrapper binary for an hls version, if any.-hlsWrapperBinary :: (MonadReader env m, HasDirs env, MonadThrow m, MonadIO m)-                 => Version-                 -> m (Maybe FilePath)-hlsWrapperBinary ver = do-  Dirs {..}  <- getDirs-  wrapper <- liftIO $ handleIO (\_ -> pure []) $ findFiles-    binDir-    (makeRegexOpts-      compExtended-      execBlank-      ([s|^haskell-language-server-wrapper-|] <> escapeVerRex ver <> E.encodeUtf8 (T.pack exeExt) <> [s|$|] :: ByteString-      )-    )-  case wrapper of-    []  -> pure Nothing-    [x] -> pure $ Just x-    _   -> throwM $ UnexpectedListLength-      "There were multiple hls wrapper binaries for a single version"----- | Get all binaries for an hls version, if any.-hlsAllBinaries :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m) => Version -> m [FilePath]-hlsAllBinaries ver = do-  hls     <- hlsServerBinaries ver Nothing-  wrapper <- hlsWrapperBinary ver-  pure (maybeToList wrapper ++ hls)------    ------------------------------------------    --[ Major version introspection (X.Y) ]---    ---------------------------------------------- | Extract (major, minor) from any version.-getMajorMinorV :: MonadThrow m => Version -> m (Int, Int)-getMajorMinorV (Version _ (Chunks (Numeric x :| Numeric y : _)) _ _) = pure (fromIntegral x, fromIntegral y)-getMajorMinorV _ = throwM $ ParseError "Could not parse X.Y from version"--matchMajor :: Version -> Int -> Int -> Bool-matchMajor v' major' minor' = case getMajorMinorV v' of-  Just (x, y) -> x == major' && y == minor'-  Nothing     -> False---- | Match PVP prefix.------ >>> matchPVPrefix [pver|8.8|] [pver|8.8.4|]--- True--- >>> matchPVPrefix [pver|8|] [pver|8.8.4|]--- True--- >>> matchPVPrefix [pver|8.10|] [pver|8.8.4|]--- False--- >>> matchPVPrefix [pver|8.10|] [pver|8.10.7|]--- True-matchPVPrefix :: PVP -> PVP -> Bool-matchPVPrefix (toL -> prefix) (toL -> full) = and $ zipWith (==) prefix full--toL :: PVP -> [Int]-toL (PVP inner) = fmap fromIntegral $ NE.toList inner----- | Get the latest installed full GHC version that satisfies the given (possibly partial)--- PVP version.-getGHCForPVP :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m)-             => PVP-             -> Maybe Text -- ^ the target triple-             -> m (Maybe GHCTargetVersion)-getGHCForPVP pvpIn mt = do-  ghcs <- rights <$> getInstalledGHCs-  -- we're permissive here... failed parse just means we have no match anyway-  let ghcs' = catMaybes $ flip fmap ghcs $ \GHCTargetVersion{..} -> do-        (pvp_, rest) <- versionToPVP _tvVersion-        pure (pvp_, rest, _tvTarget)--  getGHCForPVP' pvpIn ghcs' mt---- | Like 'getGHCForPVP', except with explicit input parameter.------ >>> getGHCForPVP' [pver|8|] installedVersions Nothing--- Just (GHCTargetVersion {_tvTarget = Nothing, _tvVersion = Version {_vEpoch = Nothing, _vChunks = Chunks (Numeric 8 :| [Numeric 10,Numeric 7]), _vRel = Just (Release (Alphanum "debug" :| [])), _vMeta = Just "lol"}})--- >>> fmap prettyShow $ getGHCForPVP' [pver|8.8|] installedVersions Nothing--- "Just 8.8.4"--- >>> fmap prettyShow $ getGHCForPVP' [pver|8.10.4|] installedVersions Nothing--- "Just 8.10.4"-getGHCForPVP' :: MonadThrow m-             => PVP-             -> [(PVP, Text, Maybe Text)] -- ^ installed GHCs-             -> Maybe Text          -- ^ the target triple-             -> m (Maybe GHCTargetVersion)-getGHCForPVP' pvpIn ghcs' mt = do-  let mResult = lastMay-                  . sortBy (\(x, _, _) (y, _, _) -> compare x y)-                  . filter-                      (\(pvp_, _, target) ->-                        target == mt && matchPVPrefix pvp_ pvpIn-                      )-                  $ ghcs'-  forM mResult $ \(pvp_, rest, target) -> do-    ver' <- pvpToVersion pvp_ rest-    pure (GHCTargetVersion target ver')----- | Get the latest available ghc for the given PVP version, which--- may only contain parts.------ >>> (fmap . fmap) (\(p, _, _) -> p) $ getLatestToolFor GHC Nothing [pver|8|] r--- Just (PVP {_pComponents = 8 :| [10,7]})--- >>> (fmap . fmap) (\(p, _, _) -> p) $ getLatestToolFor GHC Nothing [pver|8.8|] r--- Just (PVP {_pComponents = 8 :| [8,4]})--- >>> (fmap . fmap) (\(p, _, _) -> p) $ getLatestToolFor GHC Nothing [pver|8.8.4|] r--- Just (PVP {_pComponents = 8 :| [8,4]})-getLatestToolFor :: MonadThrow m-                 => Tool-                 -> Maybe Text-                 -> PVP-                 -> GHCupDownloads-                 -> m (Maybe (PVP, VersionInfo, Maybe Text))-getLatestToolFor tool target pvpIn dls = do-  let ls :: [(GHCTargetVersion, VersionInfo)]-      ls = fromMaybe [] $ preview (ix tool % to Map.toDescList) dls-  let ps :: [((PVP, Text), VersionInfo, Maybe Text)]-      ps = catMaybes $ fmap (\(v, vi) -> (,vi, _tvTarget v) <$> versionToPVP (_tvVersion v)) ls-  pure . fmap (\((pv', _), vi, mt) -> (pv', vi, mt)) . headMay . filter (\((v, _), _, t) -> matchPVPrefix pvpIn v && t == target) $ ps----    -------------    --[ Tags ]---    ----------------- | Get the tool version that has this tag. If multiple have it,--- picks the greatest version.-getTagged :: Tag-          -> Fold (Map.Map GHCTargetVersion VersionInfo) (GHCTargetVersion, VersionInfo)-getTagged tag =-  to (Map.toDescList . Map.filter (\VersionInfo {..} -> tag `elem` _viTags))-  % folding id--getByReleaseDay :: GHCupDownloads -> Tool -> Day -> Either (Maybe Day) (GHCTargetVersion, VersionInfo)-getByReleaseDay av tool day = let mvv = fromMaybe mempty $ headOf (ix tool) av-                                  mdv = Map.foldrWithKey (\k vi@VersionInfo{..} m ->-                                            maybe m (\d -> let diff = diffDays d day-                                                           in Map.insert (abs diff) (diff, (k, vi)) m) _viReleaseDay)-                                          Map.empty mvv-                              in case headMay (Map.toAscList mdv) of-                                   Nothing -> Left Nothing-                                   Just (absDiff, (diff, (k, vi)))-                                     | absDiff == 0 -> Right (k, vi)-                                     | otherwise -> Left (Just (addDays diff day))--getByReleaseDayFold :: Day -> Fold (Map.Map GHCTargetVersion VersionInfo) (GHCTargetVersion, VersionInfo)-getByReleaseDayFold day = to (Map.toDescList . Map.filter (\VersionInfo {..} -> Just day == _viReleaseDay)) % folding id--getLatest :: GHCupDownloads -> Tool -> Maybe (GHCTargetVersion, VersionInfo)-getLatest av tool = headOf (ix tool % getTagged Latest) av--getLatestPrerelease :: GHCupDownloads -> Tool -> Maybe (GHCTargetVersion, VersionInfo)-getLatestPrerelease av tool = headOf (ix tool % getTagged LatestPrerelease) av--getLatestNightly :: GHCupDownloads -> Tool -> Maybe (GHCTargetVersion, VersionInfo)-getLatestNightly av tool = headOf (ix tool % getTagged LatestNightly) av--getRecommended :: GHCupDownloads -> Tool -> Maybe (GHCTargetVersion, VersionInfo)-getRecommended av tool = headOf (ix tool % getTagged Recommended) av----- | Gets the latest GHC with a given base version.-getLatestBaseVersion :: GHCupDownloads -> PVP -> Maybe (GHCTargetVersion, VersionInfo)-getLatestBaseVersion av pvpVer =-  headOf (ix GHC % getTagged (Base pvpVer)) av-----    --------------    --[ Other ]---    ----------------intoSubdir :: (MonadReader env m, HasLog env, MonadIO m, MonadThrow m, MonadCatch m)-           => GHCupPath       -- ^ unpacked tar dir-           -> TarDir         -- ^ how to descend-           -> Excepts '[TarDirDoesNotExist] m GHCupPath-intoSubdir bdir tardir = case tardir of-  RealDir pr -> do-    whenM (fmap not . liftIO . doesDirectoryExist $ fromGHCupPath (bdir `appendGHCupPath` pr))-          (throwE $ TarDirDoesNotExist tardir)-    pure (bdir `appendGHCupPath` pr)-  RegexDir r -> do-    let rs = split (`elem` pathSeparators) r-    foldlM-      (\y x ->-        (handleIO (\_ -> pure []) . liftIO . findFiles (fromGHCupPath y) . regex $ x) >>= (\case-          []      -> throwE $ TarDirDoesNotExist tardir-          (p : _) -> pure (y `appendGHCupPath` p)) . sort-      )-      bdir-      rs-    where regex = makeRegexOpts compIgnoreCase execBlank---- | Usually @~\/.ghcup\/ghc\/\<ver\>\/bin\/@-ghcInternalBinDir :: (MonadReader env m, HasDirs env, MonadThrow m, MonadFail m, MonadIO m)-                  => GHCTargetVersion-                  -> m FilePath-ghcInternalBinDir ver = do-  ghcdir <- fromGHCupPath <$> ghcupGHCDir ver-  pure (ghcdir </> "bin")----- | Get tool files from @~\/.ghcup\/ghc\/\<ver\>\/bin\/\*@--- while ignoring @*-\<ver\>@ symlinks and accounting for cross triple prefix.------ Returns unversioned relative files without extension, e.g.:------   - @["hsc2hs","haddock","hpc","runhaskell","ghc","ghc-pkg","ghci","runghc","hp2ps"]@-ghcToolFiles :: (MonadReader env m, HasDirs env, MonadThrow m, MonadFail m, MonadIO m)-             => GHCTargetVersion-             -> Excepts '[NotInstalled] m [FilePath]-ghcToolFiles ver = do-  bindir <- ghcInternalBinDir ver--  -- fail if ghc is not installed-  whenM (fmap not $ ghcInstalled ver)-        (throwE (NotInstalled GHC ver))--  files <- liftIO (listDirectoryFiles bindir >>= filterM (doesFileExist . (bindir </>)))-  pure (getUniqueTools . groupToolFiles . fmap (dropSuffix exeExt) $ files)-- where--  groupToolFiles :: [FilePath] -> [[(FilePath, String)]]-  groupToolFiles = groupBy (\(a, _) (b, _) -> a == b) . fmap (splitOnPVP "-")--  getUniqueTools :: [[(FilePath, String)]] -> [String]-  getUniqueTools = filter (isNotAnyInfix blackListedTools) . nub . fmap fst . concatMap (filter ((== "") . snd))--  blackListedTools :: [String]-  blackListedTools = ["haddock-ghc"]--  isNotAnyInfix :: [String] -> String -> Bool-  isNotAnyInfix xs t = foldr (\a b -> not (a `isInfixOf` t) && b) True xs------ | Calls gmake if it exists in PATH, otherwise make.-make :: ( MonadThrow m-        , MonadIO m-        , MonadReader env m-        , HasDirs env-        , HasLog env-        , HasSettings env-        )-     => [String]-     -> Maybe FilePath-     -> m (Either ProcessError ())-make args workdir = make' args workdir "ghc-make" Nothing----- | Calls gmake if it exists in PATH, otherwise make.-make' :: ( MonadThrow m-         , MonadIO m-         , MonadReader env m-         , HasDirs env-         , HasLog env-         , HasSettings env-         )-      => [String]-      -> Maybe FilePath-      -> FilePath         -- ^ log filename (opened in append mode)-      -> Maybe [(String, String)] -- ^ optional environment-      -> m (Either ProcessError ())-make' args workdir logfile menv = do-  spaths    <- liftIO getSearchPath-  has_gmake <- isJust <$> liftIO (searchPath spaths "gmake")-  let mymake = if has_gmake then "gmake" else "make"-  execLogged mymake args workdir logfile menv---makeOut :: (MonadReader env m, HasDirs env, MonadIO m)-        => [String]-        -> Maybe FilePath-        -> m CapturedProcess-makeOut args workdir = do-  spaths    <- liftIO getSearchPath-  has_gmake <- isJust <$> liftIO (searchPath spaths "gmake")-  let mymake = if has_gmake then "gmake" else "make"-  executeOut mymake args workdir----- | Try to apply patches in order. The order is determined by--- a quilt series file (in the patch directory) if one exists,--- else the patches are applied in lexicographical order.--- Fails with 'PatchFailed' on first failure.-applyPatches :: (MonadReader env m, HasDirs env, HasLog env, MonadIO m)-             => FilePath   -- ^ dir containing patches-             -> FilePath   -- ^ dir to apply patches in-             -> Excepts '[PatchFailed] m ()-applyPatches pdir ddir = do-  let lexicographical = (fmap . fmap) (pdir </>) $ sort <$> findFiles-        pdir-        (makeRegexOpts compExtended-                       execBlank-                       ([s|.+\.(patch|diff)$|] :: ByteString)-        )-  let quilt = map (pdir </>) . lines <$> readFile (pdir </> "series")--  patches <- liftIO $ quilt `catchIO` (\e ->-    if isDoesNotExistError e || isPermissionError e then-      lexicographical-    else throwIO e)-  forM_ patches $ \patch' -> applyPatch patch' ddir---applyPatch :: (MonadReader env m, HasDirs env, HasLog env, MonadIO m)-           => FilePath   -- ^ Patch-           -> FilePath   -- ^ dir to apply patches in-           -> Excepts '[PatchFailed] m ()-applyPatch patch ddir = do-  lift $ logInfo $ "Applying patch " <> T.pack patch-  fmap (either (const Nothing) Just)-       (exec-         "patch"-         ["-p1", "-s", "-f", "-i", patch]-         (Just ddir)-         Nothing)-    !? PatchFailed---applyAnyPatch :: ( MonadReader env m-                 , HasDirs env-                 , HasLog env-                 , HasSettings env-                 , MonadUnliftIO m-                 , MonadCatch m-                 , MonadResource m-                 , MonadThrow m-                 , MonadMask m-                 , MonadIO m)-              => Maybe (Either FilePath [URI])-              -> FilePath-              -> Excepts '[PatchFailed, DownloadFailed, DigestError, ContentLengthError, GPGError] m ()-applyAnyPatch Nothing _                   = pure ()-applyAnyPatch (Just (Left pdir)) workdir  = liftE $ applyPatches pdir workdir-applyAnyPatch (Just (Right uris)) workdir = do-  tmpUnpack <- fromGHCupPath <$> lift withGHCupTmpDir-  forM_ uris $ \uri -> do-    patch <- liftE $ download uri Nothing Nothing Nothing tmpUnpack Nothing False-    liftE $ applyPatch patch workdir----- | https://gitlab.haskell.org/ghc/ghc/-/issues/17353-darwinNotarization :: (MonadReader env m, HasDirs env, MonadIO m)-                   => Platform-                   -> FilePath-                   -> m (Either ProcessError ())-darwinNotarization Darwin path = exec-  "/usr/bin/xattr"-  ["-r", "-d", "com.apple.quarantine", path]-  Nothing-  Nothing-darwinNotarization _ _ = pure $ Right ()-----getChangeLog :: GHCupDownloads -> Tool -> ToolVersion -> Maybe URI-getChangeLog dls tool (GHCVersion v') =-  preview (ix tool % ix v' % viChangeLog % _Just) dls-getChangeLog dls tool (ToolVersion (mkTVer -> v')) =-  preview (ix tool % ix v' % viChangeLog % _Just) dls-getChangeLog dls tool (ToolTag tag) =-  preview (ix tool % pre (getTagged tag) % to snd % viChangeLog % _Just) dls-getChangeLog dls tool (ToolDay day) =-  preview (ix tool % pre (getByReleaseDayFold day) % to snd % viChangeLog % _Just) dls----- | Execute a build action while potentially cleaning up:------   1. the build directory, depending on the KeepDirs setting-runBuildAction :: ( MonadReader env m-                  , HasDirs env-                  , HasSettings env-                  , MonadIO m-                  , MonadMask m-                  , HasLog env-                  , MonadUnliftIO m-                  , MonadFail m-                  , MonadCatch m-                  )-               => GHCupPath        -- ^ build directory (cleaned up depending on Settings)-               -> Excepts e m a-               -> Excepts e m a-runBuildAction bdir action = do-  Settings {..} <- lift getSettings-  let exAction = do-        when (keepDirs == Never)-          $ rmBDir bdir-  v <--    flip onException (lift exAction)-    $ onE_ exAction action-  when (keepDirs == Never || keepDirs == Errors) $ lift $ rmBDir bdir-  pure v----- | Clean up the given directory if the action fails,--- depending on the Settings.-cleanUpOnError :: forall e m a env .-                  ( MonadReader env m-                  , HasDirs env-                  , HasSettings env-                  , MonadIO m-                  , MonadMask m-                  , HasLog env-                  , MonadUnliftIO m-                  , MonadFail m-                  , MonadCatch m-                  )-               => GHCupPath        -- ^ build directory (cleaned up depending on Settings)-               -> Excepts e m a-               -> Excepts e m a-cleanUpOnError bdir action = do-  Settings {..} <- lift getSettings-  let exAction = when (keepDirs == Never) $ rmBDir bdir-  flip onException (lift exAction) $ onE_ exAction action----- | Remove a build directory, ignoring if it doesn't exist and gracefully--- printing other errors without crashing.-rmBDir :: (MonadReader env m, HasLog env, MonadUnliftIO m, MonadIO m) => GHCupPath -> m ()-rmBDir dir = withRunInIO (\run -> run $-           liftIO $ handleIO (\e -> run $ logWarn $-               "Couldn't remove build dir " <> T.pack (fromGHCupPath dir) <> ", error was: " <> T.pack (displayException e))-           $ hideError doesNotExistErrorType-           $ rmPathForcibly dir)---getVersionInfo :: GHCTargetVersion-               -> Tool-               -> GHCupDownloads-               -> Maybe VersionInfo-getVersionInfo v' tool =-  headOf-    ( ix tool-    % to (Map.filterWithKey (\k _ -> k == v'))-    % to Map.elems-    % _head-    )---ensureShimGen :: ( MonadMask m-                 , MonadThrow m-                 , HasLog env-                 , MonadIO m-                 , MonadReader env m-                 , HasDirs env-                 , HasSettings env-                 , HasGHCupInfo env-                 , MonadUnliftIO m-                 , MonadFail m-                 )-              => Excepts '[URIParseError, GPGError, DigestError, ContentLengthError, DownloadFailed, NoDownload] m ()-ensureShimGen-  | isWindows = do-      dirs <- lift getDirs-      let shimDownload = DownloadInfo (decUTF8Safe . serializeURIRef' $ shimGenURL) Nothing shimGenSHA Nothing Nothing Nothing-      let dl = downloadCached' shimDownload (Just "gs.exe") Nothing-      void $ (\DigestError{} -> do-          lift $ logWarn "Digest doesn't match, redownloading gs.exe..."-          lift $ logDebug ("rm -f " <> T.pack (fromGHCupPath (cacheDir dirs) </> "gs.exe"))-          lift $ hideError doesNotExistErrorType $ recycleFile (fromGHCupPath (cacheDir dirs) </> "gs.exe")-          liftE @'[URIParseError, GPGError, DigestError, ContentLengthError, DownloadFailed] $ dl-        ) `catchE` liftE @'[URIParseError, GPGError, DigestError, ContentLengthError, DownloadFailed] dl-  | otherwise = pure ()----- | Ensure ghcup directory structure exists.-ensureDirectories :: Dirs -> IO ()-ensureDirectories (Dirs baseDir binDir cacheDir logsDir confDir trashDir dbDir tmpDir _) = do-  createDirRecursive' (fromGHCupPath baseDir)-  createDirRecursive' (fromGHCupPath baseDir </> "ghc")-  createDirRecursive' (fromGHCupPath baseDir </> "hls")-  createDirRecursive' binDir-  createDirRecursive' (fromGHCupPath cacheDir)-  createDirRecursive' (fromGHCupPath logsDir)-  createDirRecursive' (fromGHCupPath confDir)-  createDirRecursive' (fromGHCupPath trashDir)-  createDirRecursive' (fromGHCupPath dbDir)-  createDirRecursive' (fromGHCupPath tmpDir)-  pure ()----- | For ghc without arch triple, this is:------    - ghc------ For ghc with arch triple:------    - <triple>-ghc (e.g. arm-linux-gnueabihf-ghc)-ghcBinaryName :: GHCTargetVersion -> String-ghcBinaryName (GHCTargetVersion (Just t) _) = T.unpack (t <> "-ghc" <> T.pack exeExt)-ghcBinaryName (GHCTargetVersion Nothing  _) = T.unpack ("ghc" <> T.pack exeExt)----- | Does basic checks for isolated installs--- Isolated Directory:---   1. if it doesn't exist -> proceed---   2. if it exists and is empty -> proceed---   3. if it exists and is non-empty -> panic and leave the house-installDestSanityCheck :: ( MonadIO m-                          , MonadCatch m-                          , MonadMask m-                          , MonadUnliftIO m-                          ) =>-                          InstallDirResolved ->-                          Excepts '[DirNotEmpty] m ()-installDestSanityCheck (IsolateDirResolved isoDir) = do-  hideErrorDef [doesNotExistErrorType] () $ do-    empty' <- lift $ runConduitRes $ getDirectoryContentsRecursiveUnsafe isoDir .| C.null-    when (not empty') (throwE $ DirNotEmpty isoDir)-installDestSanityCheck _ = pure ()----- | Returns 'Nothing' for legacy installs.-getInstalledFiles :: ( MonadIO m-                     , MonadCatch m-                     , MonadReader env m-                     , HasDirs env-                     , MonadFail m-                     )-                  => Tool-                  -> GHCTargetVersion-                  -> m (Maybe [FilePath])-getInstalledFiles t v' = hideErrorDef [doesNotExistErrorType] Nothing $ do-  f <- recordedInstallationFile t v'-  (force -> !c) <- liftIO-    (readFile f >>= evaluate)-  pure (Just $ lines c)----- | Warn if the installed and set HLS is not compatible with the installed and--- set GHC version.-warnAboutHlsCompatibility :: ( MonadReader env m-                             , HasDirs env-                             , HasLog env-                             , MonadThrow m-                             , MonadCatch m-                             , MonadIO m-                             )-                          => m ()-warnAboutHlsCompatibility = do-  supportedGHC <- hlsGHCVersions-  currentGHC   <- fmap _tvVersion <$> ghcSet Nothing-  currentHLS   <- hlsSet--  case (currentGHC, currentHLS) of-    (Just gv, Just hv) | gv `notElem` supportedGHC -> do-      logWarn $-        "GHC-" <> T.pack (prettyShow gv) <> " appears to have no corresponding HLS-" <> T.pack (prettyShow hv) <> " binary." <> "\n" <>-        "Haskell IDE support may not work." <> "\n" <>-        "You can try to either: " <> "\n" <>-        "  1. Install a different HLS version (e.g. downgrade for older GHCs)" <> "\n" <>-        "  2. Install and set one of the following GHCs: " <> T.pack (prettyShow supportedGHC) <> "\n" <>-        "  3. Let GHCup compile HLS for you, e.g. run: ghcup compile hls -g " <> T.pack (prettyShow hv) <> " --ghc " <> T.pack (prettyShow gv) <> " --cabal-update\n" <>-        "     (see https://www.haskell.org/ghcup/guide/#hls for more information)"--    _ -> return ()----    ------------    --[ Git ]---    ---------------isCommitHash :: String -> Bool-isCommitHash str' = let hex = all isHexDigit str'-                        len = length str'-                    in hex && len == 40---gitOut :: (MonadReader env m, HasLog env, MonadIO m) => [String] -> FilePath -> Excepts '[ProcessError] m T.Text-gitOut args dir = do-  CapturedProcess {..} <- lift $ executeOut "git" args (Just dir)-  case _exitCode of-    ExitSuccess   -> pure $ T.pack $ stripNewlineEnd $ T.unpack $ decUTF8Safe' _stdOut-    ExitFailure c -> do-      let pe = NonZeroExit c "git" args-      lift $ logDebug $ T.pack (prettyHFError pe)-      throwE pe--processBranches :: T.Text -> [String]-processBranches str' = let lines'   = lines (T.unpack str')-                           words'   = fmap words lines'-                           refs     = catMaybes $ fmap (`atMay` 1) words'-                           branches = catMaybes $ fmap (stripPrefix "refs/heads/") $ filter (isPrefixOf "refs/heads/") refs-                       in branches----    -------------------    --[ Versioning ]---    ----------------------- | Expand a list of version patterns describing a string such as "%v-%h".------ >>> expandVersionPattern (either (const Nothing) Just $ version "3.4.3") "a386748" "a3867484ccc391daad1a42002c3a2ba6a93c5221" "v0.1.20.0-119-ga386748" "issue-998" [CabalVer, S "-", GitHashShort, S "-", GitHashLong, S "-", GitBranchName, S "-", GitDescribe, S "-coco"]--- Version {_vEpoch = Nothing, _vChunks = Chunks (Numeric 3 :| [Numeric 4,Numeric 3]), _vRel = Just (Release (Alphanum "a386748-a3867484ccc391daad1a42002c3a2ba6a93c5221-issue-998-v0" :| [Numeric 1,Numeric 20,Alphanum "0-119-ga386748-coco"])), _vMeta = Nothing}-expandVersionPattern :: MonadFail m-                     => Maybe Version  -- ^ cabal ver-                     -> String         -- ^ git hash (short), if any-                     -> String         -- ^ git hash (long), if any-                     -> String         -- ^ git describe output, if any-                     -> String         -- ^ git branch name, if any-                     -> [VersionPattern]-                     -> m Version-expandVersionPattern cabalVer gitHashS gitHashL gitDescribe gitBranch-  = either (fail . displayException) pure . version . T.pack . go- where-  go [] = ""-  go (CabalVer:xs) = T.unpack (maybe "" prettyVer cabalVer) <> go xs-  go (GitHashShort:xs) = gitHashS <> go xs-  go (GitHashLong:xs) = gitHashL <> go xs-  go (GitDescribe:xs) = gitDescribe <> go xs-  go (GitBranchName:xs) = gitBranch <> go xs-  go (S str:xs) = str <> go xs
− lib/GHCup/Utils/Dirs.hs
@@ -1,614 +0,0 @@-{-# LANGUAGE CPP                   #-}-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE ViewPatterns          #-}-{-# LANGUAGE QuasiQuotes           #-}--{-|-Module      : GHCup.Utils.Dirs-Description : Definition of GHCup directories-Copyright   : (c) Julian Ospald, 2020-License     : LGPL-3.0-Maintainer  : hasufell@hasufell.de-Stability   : experimental-Portability : portable--}-module GHCup.Utils.Dirs-  ( getAllDirs-  , ghcupBaseDir-  , ghcupConfigFile-  , ghcupCacheDir-  , ghcupGHCBaseDir-  , ghcupGHCDir-  , ghcupHLSBaseDir-  , ghcupHLSDir-  , mkGhcupTmpDir-  , parseGHCupGHCDir-  , parseGHCupHLSDir-  , relativeSymlink-  , withGHCupTmpDir-  , getConfigFilePath-  , getConfigFilePath'-  , useXDG-  , cleanupTrash-  , ghcupMsys2BinDirs-  , ghcupMsys2BinDirs'--  , GHCupPath-  , appendGHCupPath-  , fromGHCupPath-  , createTempGHCupDirectory-  , getGHCupTmpDirs--  , removeDirectory-  , removeDirectoryRecursive-  , removePathForcibly--  , listDirectoryFiles-  , listDirectoryDirs--  -- System.Directory re-exports-  , createDirectory-  , createDirectoryIfMissing-  , renameDirectory-  , listDirectory-  , getDirectoryContents-  , getCurrentDirectory-  , setCurrentDirectory-  , withCurrentDirectory-  , getHomeDirectory-  , XdgDirectory(..)-  , getXdgDirectory-  , XdgDirectoryList(..)-  , getXdgDirectoryList-  , getAppUserDataDirectory-  , getUserDocumentsDirectory-  , getTemporaryDirectory-  , removeFile-  , renameFile-  , renamePath-  , getFileSize-  , canonicalizePath-  , makeAbsolute-  , makeRelativeToCurrentDirectory-  , doesPathExist-  , doesFileExist-  , doesDirectoryExist-  , findExecutable-  , findExecutables-  , findExecutablesInDirectories-  , findFile-  , findFileWith-  , findFilesWith-  , exeExtension-  , createFileLink-  , createDirectoryLink-  , removeDirectoryLink-  , pathIsSymbolicLink-  , getSymbolicLinkTarget-  , Permissions-  , emptyPermissions-  , readable-  , writable-  , executable-  , searchable-  , setOwnerReadable-  , setOwnerWritable-  , setOwnerExecutable-  , setOwnerSearchable-  , getPermissions-  , setPermissions-  , copyPermissions-  , getAccessTime-  , getModificationTime-  , setAccessTime-  , setModificationTime-  , isSymbolicLink-  )-where---import           GHCup.Errors-import           GHCup.Types-import           GHCup.Types.JSON               ( )-import           GHCup.Types.Optics-import           GHCup.Prelude.MegaParsec-import           GHCup.Prelude.File.Search-import           GHCup.Prelude.String.QQ-import           GHCup.Prelude.Logger.Internal (logWarn, logDebug)-#if defined(IS_WINDOWS)-import           GHCup.Prelude.Windows ( isWindows )-#else-import           GHCup.Prelude.Posix   ( isWindows )-#endif--import           Control.DeepSeq (NFData, rnf)-import           Control.Exception.Safe-import           Control.Monad-import           Control.Monad.IO.Unlift-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource hiding (throwM)-import           Data.List-import           Data.ByteString                ( ByteString )-import           Data.Bifunctor-import           Data.Maybe-import           Data.Versions-import           GHC.IO.Exception               ( IOErrorType(NoSuchThing) )-import           Data.Variant.Excepts-import           Optics hiding ( uncons )-import           Safe-import           System.Info-import           System.Directory hiding ( removeDirectory-                                         , removeDirectoryRecursive-                                         , removePathForcibly-                                         , findFiles-                                         , makeAbsolute-                                         )-import qualified System.Directory              as SD--import           System.Environment-import           System.FilePath-import           System.IO.Temp-import           Text.Regex.Posix--import qualified Data.ByteString               as BS-import qualified Data.Text                     as T-import qualified Data.Yaml.Aeson               as Y-import qualified Text.Megaparsec               as MP-import System.IO.Error (ioeGetErrorType)----    ----------------------------    --[ GHCupPath utilities ]---    ------------------------------- | A 'GHCupPath' is a safe sub-path that can be recursively deleted.------ The constructor is not exported.-newtype GHCupPath = GHCupPath FilePath-  deriving (Show, Eq, Ord)--instance NFData GHCupPath where-  rnf (GHCupPath fp) = rnf fp--appendGHCupPath :: GHCupPath -> FilePath -> GHCupPath-appendGHCupPath (GHCupPath gp) fp = GHCupPath (gp </> fp)--fromGHCupPath :: GHCupPath -> FilePath-fromGHCupPath (GHCupPath gp) = gp--createTempGHCupDirectory :: GHCupPath -> FilePath -> IO GHCupPath-createTempGHCupDirectory (GHCupPath gp) d = GHCupPath <$> createTempDirectory gp d---getGHCupTmpDirs :: IO [GHCupPath]-getGHCupTmpDirs = do-  tmpdir <- fromGHCupPath <$> ghcupTMPDir-  ghcup_dirs <- handleIO (\_ -> pure []) $ findFiles-    tmpdir-    (makeRegexOpts compExtended-                   execBlank-                   ([s|^ghcup-.*$|] :: ByteString)-    )-  pure (fmap (\p -> GHCupPath (tmpdir </> p)) $ filter (maybe False ("ghcup-" `isPrefixOf`) . lastMay . splitPath) ghcup_dirs)---    -------------------------------    --[ GHCup base directories ]---    ----------------------------------- | ~/.ghcup by default------ If 'GHCUP_USE_XDG_DIRS' is set (to anything),--- then uses 'XDG_DATA_HOME/ghcup' as per xdg spec.-ghcupBaseDir :: IO GHCupPath-ghcupBaseDir-  | isWindows = do-      bdir <- fromMaybe "C:\\" <$> lookupEnv "GHCUP_INSTALL_BASE_PREFIX"-      pure (GHCupPath (bdir </> "ghcup"))-  | otherwise = do-      xdg <- useXDG-      if xdg-        then do-          bdir <- lookupEnv "XDG_DATA_HOME" >>= \case-            Just r  -> pure r-            Nothing -> do-              home <- liftIO getHomeDirectory-              pure (home </> ".local" </> "share")-          pure (GHCupPath (bdir </> "ghcup"))-        else do-          bdir <- lookupEnv "GHCUP_INSTALL_BASE_PREFIX" >>= \case-            Just r  -> pure r-            Nothing -> liftIO getHomeDirectory-          pure (GHCupPath (bdir </> ".ghcup"))----- | ~/.ghcup by default------ If 'GHCUP_USE_XDG_DIRS' is set (to anything),--- then uses 'XDG_CONFIG_HOME/ghcup' as per xdg spec.-ghcupConfigDir :: IO GHCupPath-ghcupConfigDir-  | isWindows = ghcupBaseDir-  | otherwise = do-      xdg <- useXDG-      if xdg-        then do-          bdir <- lookupEnv "XDG_CONFIG_HOME" >>= \case-            Just r  -> pure r-            Nothing -> do-              home <- liftIO getHomeDirectory-              pure (home </> ".config")-          pure (GHCupPath (bdir </> "ghcup"))-        else do-          bdir <- lookupEnv "GHCUP_INSTALL_BASE_PREFIX" >>= \case-            Just r  -> pure r-            Nothing -> liftIO getHomeDirectory-          pure (GHCupPath (bdir </> ".ghcup"))----- | If 'GHCUP_USE_XDG_DIRS' is set (to anything),--- then uses 'XDG_BIN_HOME' env var or defaults to '~/.local/bin'--- (which, sadly is not strictly xdg spec).-ghcupBinDir :: IO FilePath-ghcupBinDir-  | isWindows = (fromGHCupPath <$> ghcupBaseDir) <&> (</> "bin")-  | otherwise = do-      xdg <- useXDG-      if xdg-        then do-          lookupEnv "XDG_BIN_HOME" >>= \case-            Just r  -> pure r-            Nothing -> do-              home <- liftIO getHomeDirectory-              pure (home </> ".local" </> "bin")-        else (fromGHCupPath <$> ghcupBaseDir) <&> (</> "bin")----- | Defaults to '~/.ghcup/cache'.------ If 'GHCUP_USE_XDG_DIRS' is set (to anything),--- then uses 'XDG_CACHE_HOME/ghcup' as per xdg spec.-ghcupCacheDir :: IO GHCupPath-ghcupCacheDir-  | isWindows = ghcupBaseDir <&> (\(GHCupPath gp) -> GHCupPath (gp </> "cache"))-  | otherwise = do-      xdg <- useXDG-      if xdg-        then do-          bdir <- lookupEnv "XDG_CACHE_HOME" >>= \case-            Just r  -> pure r-            Nothing -> do-              home <- liftIO getHomeDirectory-              pure (home </> ".cache")-          pure (GHCupPath (bdir </> "ghcup" </> "cache"))-        else ghcupBaseDir <&> (\(GHCupPath gp) -> GHCupPath (gp </> "cache"))----- | Defaults to '~/.ghcup/logs'.------ If 'GHCUP_USE_XDG_DIRS' is set (to anything),--- then uses 'XDG_CACHE_HOME/ghcup/logs' as per xdg spec.-ghcupLogsDir :: IO GHCupPath-ghcupLogsDir-  | isWindows = ghcupBaseDir <&> (\(GHCupPath gp) -> GHCupPath (gp </> "logs"))-  | otherwise = do-      xdg <- useXDG-      if xdg-        then do-          bdir <- lookupEnv "XDG_CACHE_HOME" >>= \case-            Just r  -> pure r-            Nothing -> do-              home <- liftIO getHomeDirectory-              pure (home </> ".cache")-          pure (GHCupPath (bdir </> "ghcup" </> "logs"))-        else ghcupBaseDir <&> (\(GHCupPath gp) -> GHCupPath (gp </> "logs"))----- | Defaults to '~/.ghcup/db.------ If 'GHCUP_USE_XDG_DIRS' is set (to anything),--- then uses 'XDG_CACHE_HOME/ghcup/db as per xdg spec.-ghcupDbDir :: IO GHCupPath-ghcupDbDir = ghcupBaseDir <&> (\(GHCupPath gp) -> GHCupPath (gp </> "db"))----- | '~/.ghcup/trash'.--- Mainly used on windows to improve file removal operations-ghcupRecycleDir :: IO GHCupPath-ghcupRecycleDir = ghcupBaseDir <&> (\(GHCupPath gp) -> GHCupPath (gp </> "trash"))----- | Defaults to '~/.ghcup/tmp.------ If 'GHCUP_USE_XDG_DIRS' is set (to anything),--- then uses 'XDG_CACHE_HOME/ghcup/tmp as per xdg spec.-ghcupTMPDir :: IO GHCupPath-ghcupTMPDir-  | isWindows = ghcupBaseDir <&> (\(GHCupPath gp) -> GHCupPath (gp </> "tmp"))-  | otherwise = do-      xdg <- useXDG-      if xdg-        then do-          bdir <- lookupEnv "XDG_CACHE_HOME" >>= \case-            Just r  -> pure r-            Nothing -> do-              home <- liftIO getHomeDirectory-              pure (home </> ".cache")-          pure (GHCupPath (bdir </> "ghcup" </> "tmp"))-        else ghcupBaseDir <&> (\(GHCupPath gp) -> GHCupPath (gp </> "tmp"))---ghcupMsys2Dir :: IO FilePath-ghcupMsys2Dir =-  lookupEnv "GHCUP_MSYS2" >>= \case-    Just fp -> pure fp-    Nothing -> do-      baseDir <- liftIO ghcupBaseDir-      pure (fromGHCupPath baseDir </> "msys64")--ghcupMsys2BinDirs :: (MonadFail m, MonadIO m, MonadReader env m, HasDirs env) => m [FilePath]-ghcupMsys2BinDirs = do-  Dirs{..} <- getDirs-  liftIO $ ghcupMsys2BinDirs_ msys2Dir--ghcupMsys2BinDirs' :: IO [FilePath]-ghcupMsys2BinDirs' = do-  msys2Dir <- ghcupMsys2Dir-  ghcupMsys2BinDirs_ msys2Dir--ghcupMsys2BinDirs_ :: FilePath -> IO [FilePath]-ghcupMsys2BinDirs_ msys2Dir' = do-  env <- liftIO (lookupEnv "GHCUP_MSYS2_ENV") >>= \case-    Just env -> maybe (fail parseFailMsg) pure $ readMay @MSYS2Env env-    Nothing-      | "x86_64"  <- arch -> pure MINGW64-      | "i386"    <- arch -> pure MINGW32-      | "aarch64" <- arch -> pure CLANGARM64-      | otherwise -> fail "No compatible architecture for msys2"-  pure [msys2Dir' </> toEnvDir env </> "bin", msys2Dir' </> toEnvDir MSYS </> "bin"]- where-  -- https://www.msys2.org/docs/environments/-  toEnvDir :: MSYS2Env -> FilePath-  toEnvDir MSYS       = "usr"-  toEnvDir UCRT64     = "ucrt64"-  toEnvDir CLANG64    = "clang64"-  toEnvDir CLANGARM64 = "clangarm64"-  toEnvDir CLANG32    = "clang32"-  toEnvDir MINGW64    = "mingw64"-  toEnvDir MINGW32    = "mingw32"--  parseFailMsg = "Invalid value for GHCUP_MSYS2_ENV. Valid values are: MSYS, UCRT64, CLANG64, CLANGARM64, CLANG32, MINGW64, MINGW32"---getAllDirs :: IO Dirs-getAllDirs = do-  baseDir    <- ghcupBaseDir-  binDir     <- ghcupBinDir-  cacheDir   <- ghcupCacheDir-  logsDir    <- ghcupLogsDir-  confDir    <- ghcupConfigDir-  recycleDir <- ghcupRecycleDir-  tmpDir     <- ghcupTMPDir-  dbDir      <- ghcupDbDir-  msys2Dir   <- ghcupMsys2Dir-  pure Dirs { .. }----    --------------------    --[ GHCup files ]---    ---------------------getConfigFilePath :: (MonadIO m) => m FilePath-getConfigFilePath = do-  confDir <- liftIO ghcupConfigDir-  pure $ fromGHCupPath confDir </> "config.yaml"--getConfigFilePath' :: (MonadReader env m, HasDirs env) => m FilePath-getConfigFilePath' = do-  Dirs {..} <- getDirs-  pure $ fromGHCupPath confDir </> "config.yaml"---ghcupConfigFile :: (MonadIO m)-                => Excepts '[JSONError] m UserSettings-ghcupConfigFile = do-  filepath <- getConfigFilePath-  contents <- liftIO $ handleIO (\e -> if NoSuchThing == ioeGetErrorType e then pure Nothing else liftIO $ ioError e) $ Just <$> BS.readFile filepath-  case contents of-      Nothing -> pure defaultUserSettings-      Just contents' -> liftE-        . veitherToExcepts @_ @'[JSONError]-        . either (VLeft . V) VRight-        . first (JSONDecodeError . displayException)-        . Y.decodeEither'-        $ contents'---    --------------------------    --[ GHCup directories ]---    ------------------------------ | ~/.ghcup/ghc by default.-ghcupGHCBaseDir :: (MonadReader env m, HasDirs env) => m GHCupPath-ghcupGHCBaseDir = do-  Dirs {..}  <- getDirs-  pure (baseDir `appendGHCupPath` "ghc")----- | Gets '~/.ghcup/ghc/<ghcupGHCDir>'.--- The dir may be of the form---   * armv7-unknown-linux-gnueabihf-8.8.3---   * 8.8.4-ghcupGHCDir :: (MonadReader env m, HasDirs env, MonadThrow m)-            => GHCTargetVersion-            -> m GHCupPath-ghcupGHCDir ver = do-  ghcbasedir <- ghcupGHCBaseDir-  let verdir = T.unpack $ tVerToText ver-  pure (ghcbasedir `appendGHCupPath` verdir)----- | See 'ghcupToolParser'.-parseGHCupGHCDir :: MonadThrow m => FilePath -> m GHCTargetVersion-parseGHCupGHCDir (T.pack -> fp) =-  throwEither $ MP.parse ghcTargetVerP "" fp--parseGHCupHLSDir :: MonadThrow m => FilePath -> m Version-parseGHCupHLSDir (T.pack -> fp) =-  throwEither $ MP.parse version' "" fp---- TODO: inlined from GHCup.Prelude-throwEither :: (Exception a, MonadThrow m) => Either a b -> m b-throwEither a = case a of-  Left  e -> throwM e-  Right r -> pure r---- | ~/.ghcup/hls by default, for new-style installs.-ghcupHLSBaseDir :: (MonadReader env m, HasDirs env) => m GHCupPath-ghcupHLSBaseDir = do-  Dirs {..}  <- getDirs-  pure (baseDir `appendGHCupPath` "hls")---- | Gets '~/.ghcup/hls/<hls-ver>' for new-style installs.-ghcupHLSDir :: (MonadReader env m, HasDirs env, MonadThrow m)-            => Version-            -> m GHCupPath-ghcupHLSDir ver = do-  basedir <- ghcupHLSBaseDir-  let verdir = T.unpack $ prettyVer ver-  pure (basedir `appendGHCupPath` verdir)---mkGhcupTmpDir :: ( MonadReader env m-                 , HasDirs env-                 , MonadUnliftIO m-                 , HasLog env-                 , MonadCatch m-                 , MonadThrow m-                 , MonadMask m-                 , MonadIO m)-              => m GHCupPath-mkGhcupTmpDir = GHCupPath <$> do-  Dirs { tmpDir } <- getDirs-  liftIO $ createTempDirectory (fromGHCupPath tmpDir) "ghcup"---withGHCupTmpDir :: ( MonadReader env m-                   , HasDirs env-                   , HasLog env-                   , HasSettings env-                   , MonadUnliftIO m-                   , MonadCatch m-                   , MonadResource m-                   , MonadThrow m-                   , MonadMask m-                   , MonadIO m)-                => m GHCupPath-withGHCupTmpDir = do-  Settings{keepDirs} <- getSettings-  snd <$> withRunInIO (\run ->-    run-      $ allocate-          (run mkGhcupTmpDir)-          (\fp -> if -- we don't know whether there was a failure, so can only-                     -- decide for 'Always'-                     | keepDirs == Always -> pure ()-                     | otherwise -> handleIO (\e -> run-                        $ logDebug ("Resource cleanup failed for "-                                   <> T.pack (fromGHCupPath fp)-                                   <> ", error was: "-                                   <> T.pack (displayException e)))-                        . removePathForcibly-                        $ fp))-----    ---------------    --[ Others ]---    -----------------useXDG :: IO Bool-useXDG = isJust <$> lookupEnv "GHCUP_USE_XDG_DIRS"----- | Like 'relpath'. Assumes the inputs are resolved in case of symlinks.-relativeSymlink :: FilePath  -- ^ the path in which to create the symlink-                -> FilePath  -- ^ the symlink destination-                -> FilePath-relativeSymlink p1 p2-  | isWindows = p2 -- windows quickly gets into MAX_PATH issues so we don't care about relative symlinks-  | otherwise =-    let d1      = splitDirectories p1-        d2      = splitDirectories p2-        common  = takeWhile (\(x, y) -> x == y) $ zip d1 d2-        cPrefix = drop (length common) d1-    in  joinPath (replicate (length cPrefix) "..")-          <> joinPath ([pathSeparator] : drop (length common) d2)---cleanupTrash :: ( MonadIO m-                , MonadMask m-                , MonadReader env m-                , HasLog env-                , HasDirs env-                , HasSettings env-                )-             => m ()-cleanupTrash = do-  Dirs { recycleDir } <- getDirs-  contents <- liftIO $ listDirectory (fromGHCupPath recycleDir)-  if null contents-  then pure ()-  else do-    logWarn ("Removing leftover files in " <> T.pack (fromGHCupPath recycleDir))-    forM_ contents (\fp -> handleIO (\e ->-        logDebug ("Resource cleanup failed for " <> T.pack fp <> ", error was: " <> T.pack (displayException e))-      ) $ liftIO $ removePathForcibly (recycleDir `appendGHCupPath` fp))----- | List *actual files* in a directory, ignoring empty files and a couple--- of blacklisted files, such as '.DS_Store' on mac.-listDirectoryFiles :: FilePath -> IO [FilePath]-listDirectoryFiles fp = do-  listDirectory fp >>= filterM (doesFileExist . (fp </>)) <&> filter (\fp' -> not (isHidden fp') && not (isBlacklisted fp'))---- | List *actual directories* in a directory, ignoring empty directories and a couple--- of blacklisted files, such as '.DS_Store' on mac.-listDirectoryDirs :: FilePath -> IO [FilePath]-listDirectoryDirs fp = do-  listDirectory fp >>= filterM (doesDirectoryExist . (fp </>)) <&> filter (\fp' -> not (isHidden fp') && not (isBlacklisted fp'))--isHidden :: FilePath -> Bool-isHidden fp'-  | isWindows = False-  | Just ('.', _) <- uncons fp' = True-  | otherwise = False--isBlacklisted :: FilePath -> Bool-{- HLINT ignore "Use ==" -}-isBlacklisted fp' = fp' `elem` [".DS_Store"]------ System.Directory re-exports with GHCupPath--removeDirectory :: GHCupPath -> IO ()-removeDirectory (GHCupPath fp) = SD.removeDirectory fp--removeDirectoryRecursive :: GHCupPath -> IO ()-removeDirectoryRecursive (GHCupPath fp) = SD.removeDirectoryRecursive fp--removePathForcibly :: GHCupPath -> IO ()-removePathForcibly (GHCupPath fp) = SD.removePathForcibly fp----
− lib/GHCup/Utils/Dirs.hs-boot
@@ -1,37 +0,0 @@-module GHCup.Utils.Dirs- ( GHCupPath- , appendGHCupPath- , fromGHCupPath- , createTempGHCupDirectory- , removeDirectory- , removeDirectoryRecursive- , removePathForcibly- )- where--import Control.DeepSeq (NFData)----- | A 'GHCupPath' is a safe sub-path that can be recursively deleted.-newtype GHCupPath = GHCupPath FilePath--instance Show GHCupPath where--instance Eq GHCupPath where--instance Ord GHCupPath where--instance NFData GHCupPath where--appendGHCupPath :: GHCupPath -> FilePath -> GHCupPath--fromGHCupPath :: GHCupPath -> FilePath--createTempGHCupDirectory :: GHCupPath -> FilePath -> IO GHCupPath--removeDirectory :: GHCupPath -> IO ()--removeDirectoryRecursive :: GHCupPath -> IO ()--removePathForcibly :: GHCupPath -> IO ()-
− lib/GHCup/Utils/Output.hs
@@ -1,116 +0,0 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE RankNTypes  #-}--module GHCup.Utils.Output where--import Data.Void-import Data.Char-import Control.Applicative--import qualified Data.Text as T-import qualified Text.Megaparsec               as MP-import qualified Text.Megaparsec.Char          as MPC-import qualified System.Console.Terminal.Size  as TP----- | Checks whether the given text lines fit in the terminal window.--- Returns 'Nothing' if the terminal size could not be determined (e.g. bc we're--- part of a pipe).-fitsInTerminal :: [T.Text] -> IO (Maybe Bool)-fitsInTerminal text = fmap (\(TP.Window h _) -> length text <= h - 2) <$> TP.size---- | Like 'fitsInTerminal', but takes a single text blob.-fitsInTerminal' :: T.Text -> IO (Maybe Bool)-fitsInTerminal' = fitsInTerminal . T.lines--padTo :: String -> Int -> String-padTo str x =-  let lstr = strWidth str-      add' = x - lstr-  in  if add' < 0 then str else str ++ replicate add' ' '----- | Calculate the render width of a string, considering--- wide characters (counted as double width), ANSI escape codes--- (not counted), and line breaks (in a multi-line string, the longest--- line determines the width).-strWidth :: String -> Int-strWidth =-  maximum-    . (0 :)-    . map (foldr (\a b -> charWidth a + b) 0)-    . lines-    . stripAnsi---- | Strip ANSI escape sequences from a string.------ >>> stripAnsi "\ESC[31m-1\ESC[m"--- "-1"-stripAnsi :: String -> String-stripAnsi s' =-  case-      MP.parseMaybe (many $ "" <$ MP.try ansi <|> pure <$> MP.anySingle) s'-    of-      Nothing -> error "Bad ansi escape"  -- PARTIAL: should not happen-      Just xs -> concat xs- where-    -- This parses lots of invalid ANSI escape codes, but that should be fine-  ansi =-    MPC.string "\ESC[" *> digitSemicolons *> suffix MP.<?> "ansi" :: MP.Parsec-        Void-        String-        Char-  digitSemicolons = MP.takeWhileP Nothing (\c -> isDigit c || c == ';')-  suffix = MP.oneOf ['A', 'B', 'C', 'D', 'H', 'J', 'K', 'f', 'm', 's', 'u']---- | Get the designated render width of a character: 0 for a combining--- character, 1 for a regular character, 2 for a wide character.--- (Wide characters are rendered as exactly double width in apps and--- fonts that support it.) (From Pandoc.)-charWidth :: Char -> Int-charWidth c = case c of-  _ | c < '\x0300'                     -> 1-    | c >= '\x0300' && c <= '\x036F'   -> 0-    |  -- combining-      c >= '\x0370' && c <= '\x10FC'   -> 1-    | c >= '\x1100' && c <= '\x115F'   -> 2-    | c >= '\x1160' && c <= '\x11A2'   -> 1-    | c >= '\x11A3' && c <= '\x11A7'   -> 2-    | c >= '\x11A8' && c <= '\x11F9'   -> 1-    | c >= '\x11FA' && c <= '\x11FF'   -> 2-    | c >= '\x1200' && c <= '\x2328'   -> 1-    | c >= '\x2329' && c <= '\x232A'   -> 2-    | c >= '\x232B' && c <= '\x2E31'   -> 1-    | c >= '\x2E80' && c <= '\x303E'   -> 2-    | c == '\x303F'                    -> 1-    | c >= '\x3041' && c <= '\x3247'   -> 2-    | c >= '\x3248' && c <= '\x324F'   -> 1-    | -- ambiguous-      c >= '\x3250' && c <= '\x4DBF'   -> 2-    | c >= '\x4DC0' && c <= '\x4DFF'   -> 1-    | c >= '\x4E00' && c <= '\xA4C6'   -> 2-    | c >= '\xA4D0' && c <= '\xA95F'   -> 1-    | c >= '\xA960' && c <= '\xA97C'   -> 2-    | c >= '\xA980' && c <= '\xABF9'   -> 1-    | c >= '\xAC00' && c <= '\xD7FB'   -> 2-    | c >= '\xD800' && c <= '\xDFFF'   -> 1-    | c >= '\xE000' && c <= '\xF8FF'   -> 1-    | -- ambiguous-      c >= '\xF900' && c <= '\xFAFF'   -> 2-    | c >= '\xFB00' && c <= '\xFDFD'   -> 1-    | c >= '\xFE00' && c <= '\xFE0F'   -> 1-    | -- ambiguous-      c >= '\xFE10' && c <= '\xFE19'   -> 2-    | c >= '\xFE20' && c <= '\xFE26'   -> 1-    | c >= '\xFE30' && c <= '\xFE6B'   -> 2-    | c >= '\xFE70' && c <= '\xFEFF'   -> 1-    | c >= '\xFF01' && c <= '\xFF60'   -> 2-    | c >= '\xFF61' && c <= '\x16A38'  -> 1-    | c >= '\x1B000' && c <= '\x1B001' -> 2-    | c >= '\x1D000' && c <= '\x1F1FF' -> 1-    | c >= '\x1F200' && c <= '\x1F251' -> 2-    | c >= '\x1F300' && c <= '\x1F773' -> 1-    | c >= '\x20000' && c <= '\x3FFFD' -> 2-    | otherwise                        -> 1
− lib/GHCup/Utils/Pager.hs
@@ -1,65 +0,0 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE RankNTypes  #-}--module GHCup.Utils.Pager where--import System.Environment-import GHCup.Utils.Dirs (findExecutable)-import Data.Foldable (asum)-import System.Process-import System.Exit-import System.IO-import Data.Text (Text)-import qualified Data.Text.IO as T-import Control.Monad (forM_, (<=<))-import Control.Exception (IOException, try)-import GHCup.Utils.Output-import qualified Data.Text as T---getPager :: IO (Maybe FilePath)-getPager = do-  lookupEnv "GHCUP_PAGER" >>= \case-    Just r  -> pure $ Just r-    Nothing -> lookupEnv "PAGER" >>= \case-      Just r' -> pure $ Just r'-      Nothing ->-        let pagers = ["most", "more", "less"]-        in fmap (either (const Nothing) Just)-           . try @IOException-           . asum-           . fmap (maybe (fail "could not find") pure <=< findExecutable)-           $ pagers---- 'more' reads from STDERR, and requires std_err to be 'Inherit'-sendToPager :: FilePath -> [Text] -> IO (Either IOException ())-sendToPager pager text = try @IOException-    $ withCreateProcess (shell pager) { std_in = CreatePipe-                                      , std_err = Inherit-                                      , std_out = Inherit-                                      , delegate_ctlc = True-                                      }-    $ \(Just stdinH) _ _ ph -> do-        forM_ text $ T.hPutStrLn stdinH-        hClose stdinH-        exitCode <- waitForProcess ph-        case exitCode of-          ExitFailure i -> fail ("Pager exited with exit code " <> show i)-          _ -> pure ()---sendToPager' :: Maybe FilePath -> [Text] -> IO ()-sendToPager' (Just pager) text = do-  fits <- fitsInTerminal text-  case fits of-    Just True -> do-      T.putStr $ T.unlines text-    _ -> sendToPager pager text >>= \case-      Right _ -> pure ()-      Left _ -> do-        T.putStrLn $ T.unlines text-sendToPager' _ text =-  forM_ text T.putStrLn-
− lib/GHCup/Utils/Parsers.hs
@@ -1,502 +0,0 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE DuplicateRecordFields #-}-{-# LANGUAGE ViewPatterns      #-}--module GHCup.Utils.Parsers where---import           GHCup.Errors-import           GHCup.Types-import           GHCup.Types.Optics-import           GHCup.List-import           GHCup.Utils-import           GHCup.Prelude-import           GHCup.Prelude.Logger-import           GHCup.Prelude.Attoparsec as AP-import           GHCup.Prelude.MegaParsec as MP--import           Control.Applicative ((<|>), Alternative(..))-import           Control.Monad (forM, when)-import           Control.Exception.Safe-#if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail             ( MonadFail )-#endif-import           Control.Monad.Reader-import           Data.Aeson-import qualified Data.Attoparsec.ByteString as AP-#if MIN_VERSION_aeson(2,0,0)-#else-import qualified Data.HashMap.Strict as KM-#endif-import           Data.Bifunctor-import           Data.Char               as C-import           Data.Either-import           Data.Functor-import           Data.List                      ( sort, sortBy )-import           Data.Maybe-import           Data.Text                      ( Text )-import           Data.Time.Calendar             ( Day )-import           Data.Time.Format               ( parseTimeM, defaultTimeLocale )-import           Data.Versions-import           Data.Void-import           Data.Variant.Excepts-import           Optics                  hiding ( set )-import           Prelude                 hiding ( appendFile )-import           Safe-import           System.FilePath-import           URI.ByteString          hiding (parseURI)--import qualified Data.ByteString.UTF8          as UTF8-import qualified Data.Text                     as T-import qualified Data.Text.Lazy.Encoding       as LE-import qualified Data.Text.Lazy                as LT-import qualified Text.Megaparsec               as MP-import GHCup.Version---- $setup--- >>> :set -XOverloadedStrings--- >>> :set -XDataKinds--- >>> :set -XTypeApplications--- >>> :set -XQuasiQuotes--- >>> import System.Directory--- >>> import URI.ByteString--- >>> import qualified Data.Text as T--- >>> import GHCup.Prelude--- >>> import GHCup.Download--- >>> import GHCup.Version--- >>> import GHCup.Errors--- >>> import GHCup.Types--- >>> import GHCup.Utils.Dirs--- >>> import GHCup.Types.Optics--- >>> import Data.Versions--- >>> import Optics--- >>> import GHCup.Prelude.Version.QQ--- >>> import qualified Data.Text.Encoding as E--- >>> import qualified Data.Map.Strict               as M--- >>> import Control.Monad.Reader--- >>> import Data.Variant.Excepts--- >>> import Text.PrettyPrint.HughesPJClass ( prettyShow )--- >>> let lc = LoggerConfig { lcPrintDebug = False, consoleOutter = mempty, fileOutter = mempty, fancyColors = False }--- >>> dirs' <- getAllDirs--- >>> let installedVersions = [ ([pver|8.10.7|], "-debug+lol", Nothing), ([pver|8.10.4|], "", Nothing), ([pver|8.8.4|], "", Nothing), ([pver|8.8.3|], "", Nothing) ]--- >>> let settings = defaultSettings { cache = True, metaCache = 0, noNetwork = True }--- >>> let leanAppState = LeanAppState settings dirs' defaultKeyBindings lc--- >>> cwd <- getCurrentDirectory--- >>> (Right ref) <- pure $ GHCup.Utils.parseURI $ "file://" <> E.encodeUtf8 (T.pack cwd) <> "/data/metadata/" <> (urlBaseName . view pathL' $ ghcupURL)--- >>> (Right ref') <- pure $ GHCup.Utils.parseURI $ "file://" <> E.encodeUtf8 (T.pack cwd) <> "/data/metadata/" <> (urlBaseName . view pathL' $ channelURL PrereleasesChannel)--- >>> (VRight r) <- (fmap . fmap) _ghcupDownloads $ flip runReaderT leanAppState . runE @'[DigestError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError, ContentLengthError] $ liftE (getBase ref) >>= liftE . decodeMetadata @GHCupInfo--- >>> (VRight r') <- (fmap . fmap) _ghcupDownloads $ flip runReaderT leanAppState . runE @'[DigestError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError, ContentLengthError] $ liftE (getBase ref') >>= liftE . decodeMetadata @GHCupInfo--- >>> let rr = M.unionsWith (M.unionWith (\_ b2 -> b2)) [r, r']--- >>> let go = flip runReaderT leanAppState . fmap (tVerToText . fst)---    --------------    --[ Types ]---    ----------------- a superset of ToolVersion-data SetToolVersion = SetGHCVersion GHCTargetVersion-                    | SetToolVersion Version-                    | SetToolTag Tag-                    | SetToolDay Day-                    | SetRecommended-                    | SetNext-                    deriving (Eq, Show)--prettyToolVer :: ToolVersion -> String-prettyToolVer (GHCVersion v')  = T.unpack $ tVerToText v'-prettyToolVer (ToolVersion v') = T.unpack $ prettyVer v'-prettyToolVer (ToolTag t)      = show t-prettyToolVer (ToolDay day)    = show day--toSetToolVer :: Maybe ToolVersion -> SetToolVersion-toSetToolVer (Just (GHCVersion v')) = SetGHCVersion v'-toSetToolVer (Just (ToolVersion v')) = SetToolVersion v'-toSetToolVer (Just (ToolTag t')) = SetToolTag t'-toSetToolVer (Just (ToolDay d')) = SetToolDay d'-toSetToolVer Nothing = SetRecommended---platformParser :: String -> Either String PlatformRequest-platformParser s' = case MP.parse (platformP <* MP.eof) "" (T.pack s') of-  Right r -> pure r-  Left  e -> Left $ errorBundlePretty e- where-  archP :: MP.Parsec Void Text Architecture-  archP = choice' ((\x -> MP.chunk (T.pack $ archToString x) $> x) <$> ([minBound..maxBound] :: [Architecture]))-  platformP :: MP.Parsec Void Text PlatformRequest-  platformP = choice'-    [ (`PlatformRequest` FreeBSD)-    <$> (archP <* MP.chunk "-")-    <*> (  MP.chunk "portbld"-        *> (   MP.try (Just <$> verP (MP.chunk "-freebsd" <* MP.eof))-           <|> pure Nothing-           )-        <* MP.chunk "-freebsd"-        )-    , (`PlatformRequest` Darwin)-    <$> (archP <* MP.chunk "-")-    <*> (  MP.chunk "apple"-        *> (   MP.try (Just <$> verP (MP.chunk "-darwin" <* MP.eof))-           <|> pure Nothing-           )-        <* MP.chunk "-darwin"-        )-    , (\a d mv -> PlatformRequest a (Linux d) mv)-    <$> (archP <* MP.chunk "-")-    <*> distroP-    <*> ((MP.try (Just <$> verP (MP.chunk "-linux" <* MP.eof)) <|> pure Nothing-         )-        <* MP.chunk "-linux"-        )-    , (\a -> PlatformRequest a Windows Nothing)-    <$> ((archP <* MP.chunk "-")-        <* (MP.chunk "unknown-mingw32" <|> MP.chunk "unknown-windows" <|> MP.chunk "windows"))-    ]-  distroP :: MP.Parsec Void Text LinuxDistro-  distroP = choice' ((\d -> MP.chunk (T.pack $ distroToString d) $> d) <$> allDistros)---uriParser :: String -> Either String URI-uriParser = first show . parseURI . UTF8.fromString---absolutePathParser :: FilePath -> Either String FilePath-absolutePathParser f = case isValid f && isAbsolute f of-              True -> Right $ normalise f-              False -> Left "Please enter a valid absolute filepath."--isolateParser :: FilePath -> Either String FilePath-isolateParser f = case isValid f && isAbsolute f of-              True -> Right $ normalise f-              False -> Left "Please enter a valid filepath for isolate dir."---- this accepts cross prefix-ghcVersionTagEither :: String -> Either String ToolVersion-ghcVersionTagEither s' =-  second ToolDay (dayParser s') <|> second ToolTag (tagEither s') <|> second GHCVersion (ghcVersionEither s')---- this ignores cross prefix-toolVersionTagEither :: String -> Either String ToolVersion-toolVersionTagEither s' =-  second ToolDay (dayParser s') <|> second ToolTag (tagEither s') <|> second ToolVersion (toolVersionEither s')--tagEither :: String -> Either String Tag-tagEither s' = case fmap toLower s' of-  "recommended"              -> Right Recommended-  "latest"                   -> Right Latest-  "latest-prerelease"        -> Right LatestPrerelease-  "latest-nightly"           -> Right LatestNightly-  ('b':'a':'s':'e':'-':ver') -> case pvp (T.pack ver') of-                                  Right x -> Right (Base x)-                                  Left  _ -> Left $ "Invalid PVP version for base " <> ver'-  other                      -> Left $ "Unknown tag " <> other---ghcVersionEither :: String -> Either String GHCTargetVersion-ghcVersionEither =-  first (const "Not a valid version") . MP.parse ghcTargetVerP "" . T.pack--toolVersionEither :: String -> Either String Version-toolVersionEither =-  first (const "Not a valid version") . MP.parse (version' <* MP.eof) "" . T.pack---toolParser :: String -> Either String Tool-toolParser s' | t == T.pack "ghc"   = Right GHC-              | t == T.pack "cabal" = Right Cabal-              | t == T.pack "hls"   = Right HLS-              | t == T.pack "stack" = Right Stack-              | otherwise           = Left ("Unknown tool: " <> s')-  where t = T.toLower (T.pack s')--dayParser :: String -> Either String Day-dayParser s = maybe (Left $ "Could not parse \"" <> s <> "\". Expected format is: YYYY-MM-DD") Right-            $ parseTimeM True defaultTimeLocale "%Y-%-m-%-d" s---criteriaParser :: String -> Either String ListCriteria-criteriaParser s' | t == T.pack "installed"   = Right $ ListInstalled True-                  | t == T.pack "set"         = Right $ ListSet True-                  | t == T.pack "available"   = Right $ ListAvailable True-                  | t == T.pack "+installed"  = Right $ ListInstalled True-                  | t == T.pack "+set"        = Right $ ListSet True-                  | t == T.pack "+available"  = Right $ ListAvailable True-                  | t == T.pack "-installed"  = Right $ ListInstalled False-                  | t == T.pack "-set"        = Right $ ListSet False-                  | t == T.pack "-available"  = Right $ ListAvailable False-                  | otherwise                 = Left ("Unknown criteria: " <> s')-  where t = T.toLower (T.pack s')----keepOnParser :: String -> Either String KeepDirs-keepOnParser s' | t == T.pack "always" = Right Always-                | t == T.pack "errors" = Right Errors-                | t == T.pack "never"  = Right Never-                | otherwise            = Left ("Unknown keep value: " <> s')-  where t = T.toLower (T.pack s')---downloaderParser :: String -> Either String Downloader-downloaderParser s' | t == T.pack "curl"     = Right Curl-                    | t == T.pack "wget"     = Right Wget-#if defined(INTERNAL_DOWNLOADER)-                    | t == T.pack "internal" = Right Internal-#endif-                    | otherwise = Left ("Unknown downloader value: " <> s')-  where t = T.toLower (T.pack s')--gpgParser :: String -> Either String GPGSetting-gpgParser s' | t == T.pack "strict" = Right GPGStrict-             | t == T.pack "lax"    = Right GPGLax-             | t == T.pack "none"   = Right GPGNone-             | otherwise = Left ("Unknown gpg setting value: " <> s')-  where t = T.toLower (T.pack s')----overWriteVersionParser :: String -> Either String [VersionPattern]-overWriteVersionParser = first (const "Not a valid version pattern") . MP.parse (MP.many versionPattern <* MP.eof) "" . T.pack- where-  versionPattern :: MP.Parsec Void Text VersionPattern-  versionPattern = do-    str' <- T.unpack <$> MP.takeWhileP Nothing (/= '%')-    if str' /= mempty-    then pure (S str')-    else     fmap (const CabalVer)      v_cabal-         <|> fmap (const GitBranchName) b_name-         <|> fmap (const GitHashShort)  s_hash-         <|> fmap (const GitHashLong)   l_hash-         <|> fmap (const GitDescribe)   g_desc-         <|> ((\a b -> S (a : T.unpack b)) <$> MP.satisfy (const True) <*> MP.takeWhileP Nothing (== '%')) -- invalid pattern, e.g. "%k"-   where-    v_cabal = MP.chunk "%v"-    b_name  = MP.chunk "%b"-    s_hash  = MP.chunk "%h"-    l_hash  = MP.chunk "%H"-    g_desc  = MP.chunk "%g"--    ------------------    --[ Utilities ]---    --------------------fromVersion :: ( HasLog env-               , MonadFail m-               , MonadReader env m-               , HasGHCupInfo env-               , HasDirs env-               , MonadThrow m-               , MonadIO m-               , MonadCatch m-               )-            => Maybe ToolVersion-            -> GuessMode-            -> Tool-            -> Excepts-                 '[ TagNotFound-                  , DayNotFound-                  , NextVerNotFound-                  , NoToolVersionSet-                  ] m (GHCTargetVersion, Maybe VersionInfo)-fromVersion tv = fromVersion' (toSetToolVer tv)--fromVersion' :: ( HasLog env-                , MonadFail m-                , MonadReader env m-                , HasGHCupInfo env-                , HasDirs env-                , MonadThrow m-                , MonadIO m-                , MonadCatch m-                )-             => SetToolVersion-             -> GuessMode-             -> Tool-             -> Excepts-                  '[ TagNotFound-                   , DayNotFound-                   , NextVerNotFound-                   , NoToolVersionSet-                   ] m (GHCTargetVersion, Maybe VersionInfo)-fromVersion' SetRecommended _ tool = do-  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-  second Just <$> getRecommended dls tool-    ?? TagNotFound Recommended tool-fromVersion' (SetGHCVersion v) guessMode tool = do-  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-  lift $ guessFullVersion dls v tool guessMode-fromVersion' (SetToolVersion (mkTVer -> v)) guessMode tool = do-  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-  lift $ guessFullVersion dls v tool guessMode-fromVersion' (SetToolTag Latest) _ tool = do-  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-  second Just <$> getLatest dls tool ?? TagNotFound Latest tool-fromVersion' (SetToolDay day) _ tool = do-  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-  second Just <$> case getByReleaseDay dls tool day of-                          Left ad -> throwE $ DayNotFound day tool ad-                          Right v -> pure v-fromVersion' (SetToolTag LatestPrerelease) _ tool = do-  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-  second Just <$> getLatestPrerelease dls tool ?? TagNotFound LatestPrerelease tool-fromVersion' (SetToolTag LatestNightly) _ tool = do-  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-  second Just <$> getLatestNightly dls tool ?? TagNotFound LatestNightly tool-fromVersion' (SetToolTag Recommended) _ tool = do-  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-  second Just <$> getRecommended dls tool ?? TagNotFound Recommended tool-fromVersion' (SetToolTag (Base pvp'')) _ GHC = do-  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-  second Just <$> getLatestBaseVersion dls pvp'' ?? TagNotFound (Base pvp'') GHC-fromVersion' SetNext _ tool = do-  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo-  next <- case tool of-    GHC -> do-      set <- fmap _tvVersion $ ghcSet Nothing !? NoToolVersionSet tool-      ghcs <- rights <$> lift getInstalledGHCs-      (headMay-        . tail-        . dropWhile (\GHCTargetVersion {..} -> _tvVersion /= set)-        . cycle-        . sortBy (\x y -> compare (_tvVersion x) (_tvVersion y))-        . filter (\GHCTargetVersion {..} -> isNothing _tvTarget)-        $ ghcs) ?? NoToolVersionSet tool-    Cabal -> do-      set <- cabalSet !? NoToolVersionSet tool-      cabals <- rights <$> lift getInstalledCabals-      (fmap (GHCTargetVersion Nothing)-        . headMay-        . tail-        . dropWhile (/= set)-        . cycle-        . sort-        $ cabals) ?? NoToolVersionSet tool-    HLS -> do-      set <- hlsSet !? NoToolVersionSet tool-      hlses <- rights <$> lift getInstalledHLSs-      (fmap (GHCTargetVersion Nothing)-        . headMay-        . tail-        . dropWhile (/= set)-        . cycle-        . sort-        $ hlses) ?? NoToolVersionSet tool-    Stack -> do-      set <- stackSet !? NoToolVersionSet tool-      stacks <- rights <$> lift getInstalledStacks-      (fmap (GHCTargetVersion Nothing)-        . headMay-        . tail-        . dropWhile (/= set)-        . cycle-        . sort-        $ stacks) ?? NoToolVersionSet tool-    GHCup -> fail "GHCup cannot be set"-  let vi = getVersionInfo next tool dls-  pure (next, vi)-fromVersion' (SetToolTag t') _ tool =-  throwE $ TagNotFound t' tool---- | Guess the full version from an input version, by possibly--- examining the metadata and the installed versions.------ >>> go $ guessFullVersion rr (mkTVer [vver|8|]) GHC GLax--- "8.10.7"--- >>> go $ guessFullVersion rr (mkTVer [vver|8.10|]) GHC GLax--- "8.10.7"--- >>> go $ guessFullVersion rr (mkTVer [vver|8.10.7|]) GHC GLax--- "8.10.7"--- >>> go $ guessFullVersion rr (mkTVer [vver|9.12.1|]) GHC GLax--- "9.12.1"--- >>> go $ guessFullVersion rr (mkTVer [vver|8|]) GHC GStrict--- "8"-guessFullVersion :: ( HasLog env-                    , MonadFail m-                    , MonadReader env m-                    , HasDirs env-                    , MonadThrow m-                    , MonadIO m-                    , MonadCatch m-                    )-                 => GHCupDownloads-                 -> GHCTargetVersion-                 -> Tool-                 -> GuessMode-                 -> m (GHCTargetVersion, Maybe VersionInfo)-guessFullVersion dls v tool guessMode = do-  let vi = getVersionInfo v tool dls-  case pvp $ prettyVer (_tvVersion v) of -- need to be strict here-    Left _ -> pure (v, vi)-    Right pvpIn-      | (guessMode /= GStrict) && hasn't (ix tool % ix v) dls -> do-          ghcs <- if guessMode == GLaxWithInstalled then fmap rights getInstalledTools else pure []-          if v `notElem` ghcs-          then getLatestToolFor tool (_tvTarget v) pvpIn dls >>= \case-                 Just (pvp_, vi', mt) -> do-                   v' <- pvpToVersion pvp_ ""-                   when (v' /= _tvVersion v) $ logWarn ("Assuming you meant version " <> prettyVer v')-                   pure (GHCTargetVersion mt v', Just vi')-                 Nothing -> pure (v, vi)-          else pure (v, vi)-    _ -> pure (v, vi)- where-  getInstalledTools = case tool of-                        GHC -> getInstalledGHCs-                        Cabal -> (fmap . fmap) mkTVer <$> getInstalledCabals-                        HLS -> (fmap . fmap) mkTVer <$> getInstalledHLSs-                        Stack -> (fmap . fmap) mkTVer <$> getInstalledStacks-                        GHCup -> pure []---parseUrlSource :: String -> Either String [NewURLSource]-parseUrlSource s = (fromURLSource <$> parseUrlSource' s)-               <|> ((:[]) <$> parseNewUrlSource s)-               <|> parseNewUrlSources s--parseUrlSource' :: String -> Either String URLSource-parseUrlSource' "GHCupURL" = pure GHCupURL-parseUrlSource' "StackSetupURL" = pure StackSetupURL-parseUrlSource' s' = (eitherDecode . LE.encodeUtf8 . LT.pack $ s')-            <|> (fmap (OwnSource . (:[]) . Right) . first show . parseURI . UTF8.fromString $ s')--parseNewUrlSource :: String -> Either String NewURLSource-parseNewUrlSource "GHCupURL" = pure NewGHCupURL-parseNewUrlSource "StackSetupURL" = pure NewStackSetupURL-parseNewUrlSource s' = (fmap NewChannelAlias . parseChannelAlias $ s')-            <|> (eitherDecode . LE.encodeUtf8 . LT.pack $ s')-            <|> (fmap NewURI . first show . parseURI . UTF8.fromString $ s')--parseNewUrlSources :: String -> Either String [NewURLSource]-parseNewUrlSources s = case AP.parseOnly-                              (AP.parseList' <* AP.skipSpaces <* AP.endOfInput)-                              (UTF8.fromString s) of-  Right bs ->-    forM bs $ \b -> AP.parseOnly (parse <* AP.skipSpaces <* AP.endOfInput) b-  Left  e -> Left e- where-  parse :: AP.Parser NewURLSource-  parse = (NewGHCupURL <$ AP.string "GHCupURL")-      <|> (NewStackSetupURL <$ AP.string "StackSetupURL")-      <|> AP.choice ((\x -> AP.string (UTF8.fromString . T.unpack . channelAliasText $ x) $> NewChannelAlias x) <$> ([minBound..maxBound] :: [ChannelAlias]))-      <|> (NewURI <$> parseURIP)--parseChannelAlias :: String -> Either String ChannelAlias-parseChannelAlias s =-  let aliases = map (\c -> (T.unpack (channelAliasText c), c)) [minBound..maxBound]-  in case lookup s aliases of-    Just c -> Right c-    Nothing -> Left $ "Unexpected ChannelAlias: " <> s--#if MIN_VERSION_transformers(0,6,0)-instance Alternative (Either [a]) where-    empty        = Left []-    Left _ <|> n = n-    m      <|> _ = m-#endif-
− lib/GHCup/Utils/Tar.hs
@@ -1,141 +0,0 @@-{-# LANGUAGE CPP                   #-}-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE OverloadedStrings     #-}--{-|-Module      : GHCup.Utils.Tar-Description : GHCup tar abstractions-Copyright   : (c) Julian Ospald, 2024-License     : LGPL-3.0-Maintainer  : hasufell@hasufell.de-Stability   : experimental-Portability : portable--}-module GHCup.Utils.Tar where--import           GHCup.Utils.Tar.Types ( ArchiveResult(..) )-import           GHCup.Errors-import           GHCup.Prelude-import           GHCup.Prelude.Logger.Internal-import           GHCup.Types.Optics--import           Control.Monad.Catch (MonadThrow)-import           Control.Monad.Reader-import           Data.List-import           Data.Variant.Excepts-import           System.FilePath--#if defined(TAR)-import           Codec.Archive.Zip-import qualified Codec.Archive.Tar             as Tar-import qualified Codec.Archive.Tar.Entry       as Tar-import qualified Data.Map.Strict               as Map-#else-import           Codec.Archive           hiding ( Directory-                                                , ArchiveResult -- imported from "GHCup.Utils.Tar.Types"-                                                )-#endif--import qualified Codec.Compression.BZip        as BZip-import qualified Codec.Compression.GZip        as GZip-import qualified Codec.Compression.Lzma        as Lzma-import qualified Data.ByteString.Lazy          as BL-import qualified Data.Text                     as T----- | Unpack an archive to a given directory.-unpackToDir :: (MonadReader env m, HasLog env, MonadIO m, MonadThrow m)-            => FilePath       -- ^ destination dir-            -> FilePath       -- ^ archive path-            -> Excepts '[UnknownArchive-                        , ArchiveResult-                        ] m ()-unpackToDir dfp av = do-  let fn = takeFileName av-  lift $ logInfo $ "Unpacking: " <> T.pack fn <> " to " <> T.pack dfp--#if defined(TAR)-  let untar :: MonadIO m => BL.ByteString -> Excepts '[ArchiveResult] m ()-      untar = liftIO . Tar.unpack dfp . Tar.read--      rf :: MonadIO m => FilePath -> Excepts '[ArchiveResult] m BL.ByteString-      rf = liftIO . BL.readFile-#else-  let untar :: MonadIO m => BL.ByteString -> Excepts '[ArchiveResult] m ()-      untar = lEM . liftIO . runArchiveM . unpackToDirLazy dfp--      rf :: MonadIO m => FilePath -> Excepts '[ArchiveResult] m BL.ByteString-      rf = liftIO . BL.readFile-#endif--  -- extract, depending on file extension-  if-    | ".tar.gz" `isSuffixOf` fn -> liftE-      (untar . GZip.decompress =<< rf av)-    | ".tar.xz" `isSuffixOf` fn -> do-      filecontents <- liftE $ rf av-      let decompressed = Lzma.decompressWith (Lzma.defaultDecompressParams { Lzma.decompressAutoDecoder= True }) filecontents-      liftE $ untar decompressed-    | ".tar.bz2" `isSuffixOf` fn ->-      liftE (untar . BZip.decompress =<< rf av)-    | ".tar" `isSuffixOf` fn -> liftE (untar =<< rf av)-#if defined(TAR)-    | ".zip" `isSuffixOf` fn -> withArchive av (unpackInto dfp)-#else-    -- libarchive supports zip-    | ".zip" `isSuffixOf` fn -> liftE (untar =<< rf av)-#endif-    | otherwise -> throwE $ UnknownArchive fn----- | Get all files from an archive.-getArchiveFiles :: (MonadReader env m, HasLog env, MonadIO m, MonadThrow m)-                => FilePath       -- ^ archive path-                -> Excepts '[ UnknownArchive-                            , ArchiveResult-                            ] m [FilePath]-getArchiveFiles av = do-  let fn = takeFileName av-#if defined(TAR)-  let entries :: Monad m => BL.ByteString -> Excepts '[ArchiveResult] m [FilePath]-      entries =-          lE @ArchiveResult-          . Tar.foldEntries-            (\e x -> fmap (Tar.entryTarPath e :) x)-            (Right [])-            (\_ -> Left ArchiveFailed)-          . Tar.decodeLongNames-          . Tar.read--      rf :: MonadIO m => FilePath -> Excepts '[ArchiveResult] m BL.ByteString-      rf = liftIO . BL.readFile-#else-  let entries :: Monad m => BL.ByteString -> Excepts '[ArchiveResult] m [FilePath]-      entries = (fmap . fmap) filepath . lE . readArchiveBSL--      rf :: MonadIO m => FilePath -> Excepts '[ArchiveResult] m BL.ByteString-      rf = liftIO . BL.readFile-#endif--  -- extract, depending on file extension-  if-    | ".tar.gz" `isSuffixOf` fn -> liftE-      (entries . GZip.decompress =<< rf av)-    | ".tar.xz" `isSuffixOf` fn -> do-      filecontents <- liftE $ rf av-      let decompressed = Lzma.decompressWith (Lzma.defaultDecompressParams { Lzma.decompressAutoDecoder= True }) filecontents-      liftE $ entries decompressed-    | ".tar.bz2" `isSuffixOf` fn ->-      liftE (entries . BZip.decompress =<< rf av)-    | ".tar" `isSuffixOf` fn -> liftE (entries =<< rf av)-    | ".zip" `isSuffixOf` fn ->-#if defined(TAR)-        withArchive av $ do-          entries' <- getEntries-          pure $ fmap unEntrySelector $ Map.keys entries'-#else-        liftE (entries =<< rf av)-#endif-    | otherwise -> throwE $ UnknownArchive fn-
− lib/GHCup/Utils/Tar/Types.hs
@@ -1,33 +0,0 @@-{-# LANGUAGE CPP               #-}-#if defined(TAR)-{-# LANGUAGE DeriveGeneric     #-}-#endif--module GHCup.Utils.Tar.Types-  ( ArchiveResult(..)-  )-  where--#if defined(TAR)--import           Control.Exception              ( Exception )-import           Control.DeepSeq                ( NFData )-import qualified GHC.Generics                   as GHC--data ArchiveResult = ArchiveFatal-                   | ArchiveFailed-                   | ArchiveWarn-                   | ArchiveRetry-                   | ArchiveOk-                   | ArchiveEOF-  deriving (Eq, Show, GHC.Generic)--instance NFData ArchiveResult--instance Exception ArchiveResult--#else--import           Codec.Archive                  ( ArchiveResult(..) )--#endif
− lib/GHCup/Utils/URI.hs
@@ -1,61 +0,0 @@-{-# LANGUAGE CPP                   #-}-{-# LANGUAGE OverloadedStrings     #-}--{-|-Module      : GHCup.Utils.URI-Description : GHCup domain specific URI utilities-Copyright   : (c) Julian Ospald, 2024-License     : LGPL-3.0-Maintainer  : hasufell@hasufell.de-Stability   : experimental-Portability : portable--This module contains GHCup helpers specific to-URI handling.--}-module GHCup.Utils.URI where--import           GHCup.Prelude.Internal--import           Data.Bifunctor (first)-import           Data.Text                      ( Text )-import           Control.Applicative-import           Data.Attoparsec.ByteString-import           Data.ByteString-import           URI.ByteString hiding (parseURI)-import           System.URI.File-import qualified Data.Text.Encoding            as E----    ------------    --[ URI ]---    --------------parseURI :: ByteString -> Either URIParseError (URIRef Absolute)-parseURI = first OtherError . parseOnly parseURIP--parseURI' :: Text -> Either URIParseError (URIRef Absolute)-parseURI' = first OtherError . parseOnly parseURIP . E.encodeUtf8--parseURIP :: Parser (URIRef Absolute)-parseURIP = do-  ref <- (Right <$> parseFile) <|> (Left <$> uriParser laxURIParserOptions)-  case ref of-    Left (URI { uriScheme = (Scheme "file") }) ->-#if defined(IS_WINDOWS)-      fail "Invalid file URI. File URIs must be absolute (start with a drive letter or UNC path) and not contain backslashes."-#else-      fail "Invalid file URI. File URIs must be absolute."-#endif-    Left o -> pure o-    Right (FileURI (Just _) _) -> fail "File URIs with auth part are not supported!"-    Right (FileURI _ fp) -> pure $ URI (Scheme "file") Nothing fp (Query []) Nothing- where-  parseFile-#if defined(IS_WINDOWS)-    = fileURIExtendedWindowsP-#else-    = fileURIExtendedPosixP-#endif
− lib/GHCup/Version.hs
@@ -1,96 +0,0 @@-{-# LANGUAGE QuasiQuotes       #-}---{-|-Module      : GHCup.Version-Description : Version information and version handling.-Copyright   : (c) Julian Ospald, 2020-License     : LGPL-3.0-Maintainer  : hasufell@hasufell.de-Stability   : experimental-Portability : portable--}-module GHCup.Version where--import           GHCup.Types-import           Paths_ghcup (version)--import           Data.Version (Version(versionBranch))-import           URI.ByteString-import           URI.ByteString.QQ--import qualified Data.List.NonEmpty            as NE-import qualified Data.Text                     as T-import qualified Data.Versions as V-import Control.Exception.Safe (MonadThrow)-import Data.Text (Text)-import Control.Monad.Catch (throwM)-import GHCup.Errors (ParseError(..))-import Text.Megaparsec-import Data.Void (Void)---- | This reflects the API version of the YAML.------ Note that when updating this, CI requires that the file exists AND the same file exists at--- 'https://www.haskell.org/ghcup/exp/ghcup-<ver>.yaml' with some newlines added.-ghcupURL :: URI-ghcupURL = [uri|https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-0.0.9.yaml|]--stackSetupURL :: URI-stackSetupURL = [uri|https://raw.githubusercontent.com/commercialhaskell/stackage-content/master/stack/stack-setup-2.yaml|]--shimGenURL :: URI-shimGenURL = [uri|https://downloads.haskell.org/~ghcup/shimgen/shim-2.exe|]--shimGenSHA :: T.Text-shimGenSHA = T.pack "7c55e201f71860c5babea886007c8fa44b861abf50d1c07e5677eb0bda387a70"---- | The current ghcup version.-ghcUpVer :: V.PVP-ghcUpVer = V.PVP . NE.fromList . fmap fromIntegral $ versionBranch version---- | ghcup version as numeric string.-numericVer :: String-numericVer = T.unpack . V.prettyPVP $ ghcUpVer--versionCmp :: V.Versioning -> VersionCmp -> Bool-versionCmp ver1 (VR_gt ver2)   = ver1 > ver2-versionCmp ver1 (VR_gteq ver2) = ver1 >= ver2-versionCmp ver1 (VR_lt ver2)   = ver1 < ver2-versionCmp ver1 (VR_lteq ver2) = ver1 <= ver2-versionCmp ver1 (VR_eq ver2)   = ver1 == ver2--versionRange :: V.Versioning -> VersionRange -> Bool-versionRange ver' (SimpleRange cmps) = all (versionCmp ver') cmps-versionRange ver' (OrRange cmps range) =-  versionRange ver' (SimpleRange cmps) || versionRange ver' range--pvpToVersion :: MonadThrow m => V.PVP -> Text -> m V.Version-pvpToVersion pvp_ rest =-  either (\_ -> throwM $ ParseError "Couldn't convert PVP to Version") pure . V.version . (<> rest) . V.prettyPVP $ pvp_---- | Convert a version to a PVP and unparsable rest.------ -- prop> \v -> let (Just (pvp', r)) = versionToPVP v in pvpToVersion pvp' r === Just v-versionToPVP :: MonadThrow m => V.Version -> m (V.PVP, Text)-versionToPVP (V.Version (Just _) _ _ _) = throwM $ ParseError "Unexpected epoch"-versionToPVP v = case parse pvp'' "Version->PVP" $ V.prettyVer v of-  Left _  -> throwM $ ParseError "Couldn't convert Version to PVP"-  Right r -> pure r- where-   pvp'' :: Parsec Void T.Text (V.PVP, T.Text)-   pvp'' = do-     p <- V.pvp'-     s <- getParserState-     pure (p, stateInput s)--pvpFromList :: [Int] -> V.PVP-pvpFromList = V.PVP . NE.fromList . fmap fromIntegral--channelURL :: ChannelAlias -> URI-channelURL = \case-  DefaultChannel -> ghcupURL-  StackChannel -> stackSetupURL-  CrossChannel -> [uri|https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-cross-0.0.9.yaml|]-  PrereleasesChannel -> [uri|https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.9.yaml|]-  VanillaChannel -> [uri|https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-vanilla-0.0.9.yaml|]
+ lib/GHCup/Warnings.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}++module GHCup.Warnings where++import GHCup.Prelude+import GHCup.Types+import GHCup.Types.Optics++import Control.Monad.Reader           ( MonadReader )+import Data.Versions                  ( Version )+import Text.PrettyPrint.HughesPJClass ( prettyShow )++import qualified Data.Text as T+++warnAboutHlsCompatibility ::+  ( MonadReader env m+  , HasLog env+  , MonadIOish m+  )+  => Maybe Version+  -> Maybe Version+  -> [Version]+  -> m ()+warnAboutHlsCompatibility currentHLS currentGHC supportedGHC = do+  case (currentGHC, currentHLS) of+    (Just gv, Just hv) | gv `notElem` supportedGHC -> do+      logWarn $+        "GHC-" <> T.pack (prettyShow gv) <> " appears to have no corresponding HLS-" <> T.pack (prettyShow hv) <> " binary." <> "\n" <>+        "Haskell IDE support may not work." <> "\n" <>+        "You can try to either: " <> "\n" <>+        "  1. Install a different HLS version (e.g. downgrade for older GHCs)" <> "\n" <>+        "  2. Install and set one of the following GHCs: " <> T.pack (prettyShow supportedGHC) <> "\n" <>+        "  3. Let GHCup compile HLS for you, e.g. run: ghcup compile hls -g " <> T.pack (prettyShow hv) <> " --ghc " <> T.pack (prettyShow gv) <>+        "     (see https://www.haskell.org/ghcup/guide/#hls for more information)"++    _ -> return ()+
scripts/bootstrap/bootstrap-haskell view
@@ -5,7 +5,7 @@ # that affect the installation procedure.  # Main settings:-#   * BOOTSTRAP_HASKELL_NONINTERACTIVE - any nonzero value for noninteractive installation+#   * BOOTSTRAP_HASKELL_NONINTERACTIVE - any non-empty value for noninteractive installation #   * BOOTSTRAP_HASKELL_NO_UPGRADE - any nonzero value to not trigger the upgrade #   * BOOTSTRAP_HASKELL_MINIMAL - any nonzero value to only install ghcup #   * GHCUP_USE_XDG_DIRS - any nonzero value to respect The XDG Base Directory Specification@@ -22,7 +22,7 @@ #   * BOOTSTRAP_HASKELL_ADJUST_CABAL_CONFIG - whether to adjust mingw paths in cabal.config on windows #   * BOOTSTRAP_HASKELL_DOWNLOADER - which downloader to use (default: curl) #   * GHCUP_BASE_URL - the base url for ghcup binary download (use this to overwrite https://downloads.haskell.org/~ghcup with a mirror)-#   * GHCUP_MSYS2_ENV - the msys2 environment to use on windows, see https://www.msys2.org/docs/environments/ (defauts to MINGW64, MINGW32 or CLANGARM64, depending on the architecture)+#   * GHCUP_MSYS2_ENV - the msys2 environment to use on windows, see https://www.msys2.org/docs/environments/ (defaults to MINGW64, MINGW32 or CLANGARM64, depending on the architecture)  # License: LGPL-3.0 @@ -41,7 +41,7 @@  plat="$(uname -s)" arch=$(uname -m)-ghver="0.1.50.2"+ghver="0.2.1.0" : "${GHCUP_BASE_URL:=https://downloads.haskell.org/~ghcup}"  export GHCUP_SKIP_UPDATE_CHECK=yes@@ -83,6 +83,7 @@         MSYS*|MINGW*|CYGWIN*) 			: "${GHCUP_INSTALL_BASE_PREFIX:=/c}" 			GHCUP_DIR=$(cygpath -u "${GHCUP_INSTALL_BASE_PREFIX}/ghcup")+			GHCUP_CONFDIR=${GHCUP_DIR} 			GHCUP_BIN=$(cygpath -u "${GHCUP_INSTALL_BASE_PREFIX}/ghcup/bin") 			: "${GHCUP_MSYS2:=${GHCUP_DIR}/msys64}" 			set_msys2_env_dir@@ -92,9 +93,11 @@  			if [ -n "${GHCUP_USE_XDG_DIRS}" ] ; then 				GHCUP_DIR=${XDG_DATA_HOME:=$HOME/.local/share}/ghcup+				GHCUP_CONFDIR=${XDG_DATA_HOME:=$HOME/.config}/ghcup 				GHCUP_BIN=${XDG_BIN_HOME:=$HOME/.local/bin} 			else 				GHCUP_DIR=${GHCUP_INSTALL_BASE_PREFIX}/.ghcup+				GHCUP_CONFDIR=${GHCUP_DIR} 				GHCUP_BIN=${GHCUP_INSTALL_BASE_PREFIX}/.ghcup/bin 			fi 			;;@@ -338,6 +341,18 @@ 			esac 			_url=${GHCUP_BASE_URL}/${ghver}/x86_64-portbld-freebsd-ghcup-${ghver}             ;;+        "OpenBSD"|"openbsd")+			case "${arch}" in+				x86_64|amd64)+					;;+				i*86)+					die "i386 currently not supported!"+					;;+				*) die "Unknown architecture: ${arch}"+					;;+			esac+			_url=${GHCUP_BASE_URL}/${ghver}/x86_64-openbsd-ghcup-${ghver}+            ;;         "Darwin"|"darwin") 			case "${arch}" in 				x86_64|amd64)@@ -479,16 +494,27 @@     warn "" 	while true; do -        warn "[S] Skip  [D] Default (GHCup maintained)  [V] Vanilla (Upstream maintained)  [?] Help (default is \"Skip\")."+        if [ "$preexisting_config_file" -eq 1 ] ; then+            warn "[K] Keep current config  [G] GHCup maintained  [V] Vanilla (upstream maintained)  [?] Help (default is \"K\")."+        else+            warn "[G] GHCup maintained  [V] Vanilla (upstream maintained)  [?] Help (default is \"G\")."+        fi         warn "" -		read -r bashrc_answer </dev/tty+		read -r basechannel_answer </dev/tty -		case $bashrc_answer in-			[Ss]* | "")-				return 0-				;;-			[Dd]*)+        # Handle the [K]eep choice only if we actually offered it+        if [ "$preexisting_config_file" -eq 1 ] ; then+            case $basechannel_answer in+                [Kk]* | "")+                    return 0+                    ;;+            esac+        fi++        # Handle the other choices+		case $basechannel_answer in+			[Gg]* | "") 				return 1 				;; 			[Vv]*)@@ -497,22 +523,26 @@ 			*) 				echo "Possible choices are:" 				echo-				echo "[S]kip    - Do nothing and leave GHCup config as is"-                echo "[D]efault - The default channel maintained by GHCup developers"+                if [ "$preexisting_config_file" -eq 1 ] ; then+                    echo "[K]eep    - Do nothing and leave your existing GHCup config as-is"+                fi+                echo "[G]HCup   - The default channel maintained by GHCup developers"                 echo "            (receives QA and support from GHCup and may provide"                 echo "            unofficial bindists for less supported platforms)" 				echo "[V]anilla - Only contains unchanged upstream binary distributions"                 echo "            (is updated with newer releases faster since it receives no GHCup QA)" 				echo-				echo "Selecting Default or Vanilla will overwrite any pre-existing channel"-                echo "config you might have (if you've previously installed GHCup)."-				echo+                if [ "$preexisting_config_file" -eq 1 ] ; then+                    echo "Selecting GHCup or Vanilla will overwrite the channel config in"+                    echo "your existing GHCup installation."+                    echo+                fi                 echo "Please make your choice and press ENTER." 				;; 		esac 	done -	unset bashrc_answer+	unset basechannel_answer }  ask_prerelease_channel() {@@ -522,15 +552,16 @@     echo "-------------------------------------------------------------------------------"      warn ""-    warn "Do you also want to enable the pre-releases channel, getting access to."+    warn "Do you also want to enable the pre-releases channel, getting access to"     warn "alpha, betas and release candidates?"     warn ""     warn "[N] No  [Y] Yes  [?] Help (default is \"N\")."+    warn "" 	while true; do -		read -r bashrc_answer </dev/tty+		read -r prereleasechannel_answer </dev/tty -		case $bashrc_answer in+		case $prereleasechannel_answer in 			[Nn]* | "") 				return 0 				;;@@ -548,7 +579,7 @@ 		esac 	done -	unset bashrc_answer+	unset prereleasechannel_answer }  ask_cross_channel() {@@ -565,9 +596,9 @@         warn "[N] No  [Y] Yes  [?] Help (default is \"N\")."         warn "" -		read -r bashrc_answer </dev/tty+		read -r crosschannel_answer </dev/tty -		case $bashrc_answer in+		case $crosschannel_answer in 			[Nn]* | "") 				return 0 				;;@@ -577,18 +608,55 @@ 			*) 				echo "Possible choices are:" 				echo-                echo "N - No, don't enable cross (default)"-				echo "Y - Yes, enable prereleases"+                echo "N - No, don't enable the cross channel (default)"+				echo "Y - Yes, enable the cross channel" 				echo 				echo "Please make your choice and press ENTER." 				;; 		esac 	done -	unset bashrc_answer+	unset crosschannel_answer } +ask_thirdparty_channel() {+    if [ -n "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then+        return 0+    fi+	while true; do+		echo "-------------------------------------------------------------------------------" +		warn ""+        warn "Do you also want to enable the 3rdparty channel, getting access to"+        warn "to various non-core tools such as hlint, dhall and ormolu?"+        warn ""+        warn "[N] No  [Y] Yes  [?] Help (default is \"N\")."+        warn ""++		read -r thirdparty_answer </dev/tty++		case $thirdparty_answer in+			[Nn]* | "")+				return 0+				;;+			[Yy]*)+				return 1+				;;+			*)+				echo "Possible choices are:"+				echo+                echo "N - No, don't enable the cross channel (default)"+				echo "Y - Yes, enable the cross channel"+				echo+				echo "Please make your choice and press ENTER."+				;;+		esac+	done++	unset thirdparty_answer+}++ # Ask user if they want to adjust the bashrc. ask_bashrc() { 	if [ -n "${BOOTSTRAP_HASKELL_ADJUST_BASHRC}" ] ; then@@ -620,7 +688,8 @@ 				return 2 				;; 			[Nn]*)-				return 0;;+				return 0+                ;; 			*) 				echo "Possible choices are:" 				echo@@ -951,32 +1020,14 @@     read -r answer </dev/tty fi -if [ -z "${BOOTSTRAP_HASKELL_MINIMAL}" ] ; then-    ask_base_channel-    ask_base_channel_answer=$?-    if [ $ask_base_channel_answer != 0 ] ; then-        ask_prerelease_channel-        ask_prerelease_channel_answer=$?-        ask_cross_channel-        ask_cross_channel_answer=$?-    fi-fi-ask_bashrc-ask_bashrc_answer=$?-ask_cabal_config_init-ask_cabal_config_init_answer=$?-if [ -z "${BOOTSTRAP_HASKELL_MINIMAL}" ] ; then-	ask_hls-	ask_hls_answer=$?-	ask_stack-	ask_stack_answer=$?-fi+preexisting_config_file=0+test -f "${GHCUP_CONFDIR}/config.yaml" && preexisting_config_file=1  edo mkdir -p "${GHCUP_BIN}"  if command -V "ghcup" >/dev/null 2>&1 ; then     if [ -z "${BOOTSTRAP_HASKELL_NO_UPGRADE}" ] ; then-        ( _eghcup upgrade ) || download_ghcup+        download_ghcup     fi else 	download_ghcup@@ -987,8 +1038,8 @@ echo  if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then+    echo     warn "Press ENTER to proceed or ctrl-c to abort."-    warn "Installation may take a while."     echo      # Wait for user input to continue.@@ -996,6 +1047,29 @@     read -r answer </dev/tty fi +if [ -z "${BOOTSTRAP_HASKELL_MINIMAL}" ] ; then+    ask_base_channel+    ask_base_channel_answer=$?+    if [ $ask_base_channel_answer != 0 ] ; then+        ask_prerelease_channel+        ask_prerelease_channel_answer=$?+        ask_cross_channel+        ask_cross_channel_answer=$?+        ask_thirdparty_channel+        ask_thirdparty_channel_answer=$?+    fi+fi+ask_bashrc+ask_bashrc_answer=$?+ask_cabal_config_init+ask_cabal_config_init_answer=$?+if [ -z "${BOOTSTRAP_HASKELL_MINIMAL}" ] ; then+	  ask_hls+	  ask_hls_answer=$?+	  ask_stack+	  ask_stack_answer=$?+fi+ case $ask_base_channel_answer in 	1)         _eghcup config set url-source GHCupURL@@ -1016,6 +1090,13 @@ case $ask_cross_channel_answer in     1)         _eghcup config add-release-channel cross+        ;;+    *) ;;+esac++case $ask_thirdparty_channel_answer in+    1)+        _eghcup config add-release-channel 3rdparty         ;;     *) ;; esac
scripts/bootstrap/bootstrap-haskell.ps1 view
@@ -47,12 +47,12 @@     [switch]$DontWriteDesktopShortcuts,
     # Whether to disable adjusting bashrc (in msys2 env) with PATH
     [switch]$DontAdjustBashRc,
-    # The msys2 environment to use, see https://www.msys2.org/docs/environments/ (defauts to MINGW64, MINGW32 or CLANGARM64, depending on the architecture)
+    # The msys2 environment to use, see https://www.msys2.org/docs/environments/ (defaults to MINGW64, MINGW32 or CLANGARM64, depending on the architecture)
     [string]$Msys2Env
 )
 
-$DefaultMsys2Version = "20221216"
-$DefaultMsys2Hash = "18370d32b0264915c97e3d7c618f7b32d48ad80858923883fde5145acd32ca0f"
+$DefaultMsys2Version = "20250221"
+$DefaultMsys2Hash = "6d4952fd65d1924c56620355c3c7d5a1b40e3c7d7be358f6eb1017363d2dbbb1"
 
 $Silent = !$Interactive
 
@@ -561,12 +561,6 @@ 
     Exec "$env:windir\system32\taskkill.exe" /F /FI "MODULES eq msys-2.0.dll"
 
-    Print-Msg -msg 'Upgrading full system...'
-    Exec "$Bash" '-lc' 'pacman --noconfirm -Syuu'
-
-    Print-Msg -msg 'Upgrading full system twice...'
-    Exec "$Bash" '-lc' 'pacman --noconfirm -Syuu'
-
     Print-Msg -msg 'Installing Dependencies...'
     Exec "$Bash" '-lc' ('pacman --noconfirm -S --needed curl autoconf {0}' -f $PkgConf)
 
@@ -650,9 +644,15 @@ 
 	$GhcInstArgs = ('{0} -mintty -c "pacman --noconfirm -S --needed base-devel gettext autoconf make libtool automake python p7zip patch unzip"' -f $ShellType)
 	Create-Shortcut -SourceExe ('{0}\msys2_shell.cmd' -f $MsysDir) -ArgumentsToSourceExe $GhcInstArgs -DestinationPath 'Install GHC dev dependencies.lnk' -TempPath $GhcupDir
-	Create-Shortcut -SourceExe ('{0}\msys2_shell.cmd' -f $MsysDir) -ArgumentsToSourceExe $ShellType -DestinationPath 'Mingw haskell shell.lnk' -TempPath $GhcupDir
-	Create-Shortcut -SourceExe 'https://www.msys2.org/docs/package-management' -ArgumentsToSourceExe '' -DestinationPath 'Mingw package management docs.url' -TempPath $GhcupDir
+
 	$DesktopDir = [Environment]::GetFolderPath("Desktop")
+	$shellScript = (@'
+powershell.exe -ExecutionPolicy Bypass -Command ". '{0}\msys2_shell.cmd' '{1}' '-here' '-no-start' '-shell' 'bash' '-use-full-path' '-c' 'echo && echo To keep your msys2 env and bash shell up to date, run: pacman -Syuu && /usr/bin/bash -l'"
+'@ -f $MsysDir, $ShellType)
+	$null = New-Item -Path $MsysDir -Name "Haskell Shell.bat" -ItemType "file" -Force -Value $shellScript
+	Create-Shortcut -SourceExe ('{0}\Haskell Shell.bat' -f $MsysDir) -ArgumentsToSourceExe '' -DestinationPath 'Mingw haskell shell.lnk' -TempPath $GhcupDir+
+	Create-Shortcut -SourceExe 'https://www.msys2.org/docs/package-management' -ArgumentsToSourceExe '' -DestinationPath 'Mingw package management docs.url' -TempPath $GhcupDir
 	$null = New-Item -Path $DesktopDir -Name "Uninstall Haskell.ps1" -ItemType "file" -Force -Value $uninstallShortCut
 }
 
test/ghcup-test/GHCup/ArbitraryTypes.hs view
@@ -7,8 +7,11 @@   import           GHCup.Types+import           GHCup.Types.Stack+import           GHCup.Types.JSON  import           Data.ByteString                ( ByteString )+import           Data.Char                      ( toLower ) import           Data.Versions import           Data.List.NonEmpty import           Data.Time.Calendar             ( Day(..) )@@ -26,6 +29,39 @@ import qualified Data.Text.Lazy.Builder.Int    as B  +instance Arbitrary ToolVersionSpec where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary GHCupDownloads where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary Rev where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary RevisionSpec where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary VersionMetadata where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary ArchitectureSpec where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary PlatformSpec where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary PlatformVersionSpec where+  arbitrary = genericArbitrary+  shrink    = genericShrink++     -----------------     --[ utilities ]--     -----------------@@ -40,7 +76,10 @@     <*> arbitrary     <*> arbitrary +instance ToADTArbitrary ToolDescription +instance ToADTArbitrary ToolInfo+ instance ToADTArbitrary GHCupInfo  @@ -127,14 +166,81 @@     --[ ghcup arbitrary ]--     ----------------------- +instance Arbitrary ToolDescription where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary ToolInfo where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary EnvUnion where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary EnvSpec where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary ConfigSpec where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary MakeSpec where+  arbitrary = genericArbitrary+  shrink    = genericShrink+++instance Arbitrary InstallationSpecInput where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary (NonEmpty InstallFileRule) where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary InstallFileRule where+  arbitrary = suchThat genericArbitrary pred'+   where+    pred' (InstallFileRule source dest) = safePath source && maybe True safePath dest+    pred' (InstallFilePatternRule fps) = all safePath fps+  shrink    = genericShrink++instance Arbitrary (SymlinkSpec String) where+  arbitrary = suchThat genericArbitrary pred'+   where+    pred' SymlinkSpec{..} =+         safePath _slTarget+      && safeFilename _slLinkName+      && maybe True safeFilename _slSetName+  shrink    = genericShrink++instance Arbitrary SymlinkInputSpec where+  arbitrary = suchThat genericArbitrary pred'+   where+    pred' SymlinkInputSpec{..} =+         safePath _slTarget+      && safeFilename _slLinkName+      && maybe True safeFilename _slSetName+    pred' SymlinkPatternSpec{..} =+         all safePath _slTargetPattern+      && all safePath _slTargetPatternIgnore+      && safeFilename _slLinkName+      && maybe True safeFilename _slSetName+  shrink    = genericShrink+ instance Arbitrary Requirements where   arbitrary = genericArbitrary   shrink    = genericShrink -instance Arbitrary DownloadInfo where+instance Arbitrary GHCup.Types.DownloadInfo where   arbitrary = genericArbitrary   shrink    = genericShrink +instance Arbitrary GHCup.Types.Stack.DownloadInfo where+  arbitrary = genericArbitrary+  shrink    = genericShrink+ instance Arbitrary LinuxDistro where   arbitrary =     oneof (pure <$> allDistros)@@ -159,6 +265,98 @@   arbitrary = genericArbitrary   shrink    = genericShrink +instance Arbitrary UserSettings where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary PagerConfig where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary PlatformRequest where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary MetaMode where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary GPGSetting where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary Verbosity where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary URLSource where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary KeepDirs where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary Downloader where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary SetupInfo where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary UserKeyBindings where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary NewURLSource where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary ChannelAlias where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary KeyCombination where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary Key where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary Modifier where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary GHCDownloadInfo where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary ProcessSpec where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary UserInfo where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary Authority where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary DownloadMirror where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary DownloadMirrors where+  arbitrary = genericArbitrary+  shrink    = genericShrink++instance Arbitrary VersionedDownloadInfo where+  arbitrary = genericArbitrary+  shrink    = genericShrink+ instance Arbitrary (NonEmpty VersionCmp) where   arbitrary = genericArbitrary   shrink    = genericShrink@@ -172,15 +370,21 @@   shrink    = genericShrink  instance Arbitrary Tool where-  arbitrary = genericArbitrary+  arbitrary = flip suchThat pred' $ do+    ASCIIString str <- arbitrary+    pure $ Tool (toLower <$> str)+   where+    pred' = safeToolname   shrink    = genericShrink  instance Arbitrary GHCupInfo where   arbitrary = genericArbitrary   shrink    = genericShrink -instance Arbitrary GHCTargetVersion where-  arbitrary = GHCTargetVersion Nothing <$> arbitrary+instance Arbitrary TargetVersion where+  arbitrary = suchThat (TargetVersion Nothing <$> arbitrary) pred'+   where+    pred' = safeVersion   shrink    = genericShrink  
test/ghcup-test/GHCup/ParserSpec.hs view
@@ -1,20 +1,23 @@-{-# LANGUAGE OverloadedStrings    #-}-{-# LANGUAGE QuasiQuotes          #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE CPP #-}  module GHCup.ParserSpec where -import           GHCup.Types-import           GHCup.Types.JSON-import           GHCup.Prelude.Version.QQ-import           GHCup.Prelude.MegaParsec+import GHCup.Prelude.MegaParsec+import GHCup.Prelude.Version.QQ+import GHCup.Types+import GHCup.Types.JSON+    () -import           Data.List.NonEmpty             ( NonEmpty (..) )-import qualified Data.Set as Set+import           Data.Either        ( isLeft )+import           Data.List.NonEmpty ( NonEmpty (..) )+import qualified Data.Set           as Set import           Data.Versions-import qualified Text.Megaparsec as MP+import qualified Text.Megaparsec    as MP import           Text.Megaparsec -import           Test.Hspec+import Test.Hspec  spec :: Spec spec = do@@ -53,8 +56,66 @@       MP.parse ghcVersionFromPath "" "../ghc/javascript-unknown-ghcjs-9.6.2/bin/javascript-unknown-ghcjs-ghc-9.6.2" `shouldBe` Right ghcjs962       MP.parse ghcVersionFromPath "" "c:/ghc/bin/ghcup/ghc/javascript-unknown-ghcjs-9.6.2/bin/javascript-unknown-ghcjs-ghc-9.6.2" `shouldBe` Right ghcjs962 +#if defined(IS_WINDOWS)+      -- windows+      MP.parse ghcVersionFromPath "" "c:\\ghcup\\ghc\\mytag9.4.8\\bin\\ghc-9.4.8" `shouldBe` Right ghcMytag+      MP.parse ghcVersionFromPath "" "..\\ghc\\9.4.8-rc2\\bin\\ghc-9.4.8" `shouldBe` Right ghc948rc2+#endif++      -- errors+      isLeft (MP.parse ghcVersionFromPath "" "") `shouldBe` True+      isLeft (MP.parse ghcVersionFromPath "" "k") `shouldBe` True+      isLeft (MP.parse ghcVersionFromPath "" "/ghc/") `shouldBe` True++    it "toolVersionFromPath" $ do+      -- other tools+      MP.parse (toolVersionFromPath hls) "" "../hls/2.13.0.0/bin/haskell-language-server-wrapper" `shouldBe` hls2_13_0_0+      MP.parse (toolVersionFromPath cabal) "" "../cabal/3.14.1.0/cabal" `shouldBe` cabal_3_14_1_0++    it "verRevP" $ do+      -- other tools+      MP.parse verRevP "" "1.2.3-roo-rar-r100" `shouldBe` Right VersionReq {+                   _vqVersion = Version {+                     _vEpoch = Nothing,+                     _vChunks = Chunks (Numeric 1 :| [Numeric 2, Numeric 3]),+                     _vRel = Just (Release (Alphanum "roo-rar" :| [])),+                     _vMeta = Nothing+                   },+                   _vqRev = Just 100+                 }+      MP.parse verRevP "" "1.2.3-roo-rar" `shouldBe` Right VersionReq {+                   _vqVersion = Version {+                     _vEpoch = Nothing,+                     _vChunks = Chunks (Numeric 1 :| [Numeric 2, Numeric 3]),+                     _vRel = Just (Release (Alphanum "roo-rar" :| [])),+                     _vMeta = Nothing+                   },+                   _vqRev = Nothing+                 }++    it "ghcLinkVersion" $ do+      MP.parse ghcLinkVersion "" "ghc-8.10.7" `shouldBe` Right ghc8107+   where-    ghc8107 = GHCTargetVersion {_tvTarget = Nothing, _tvVersion = Version {_vEpoch = Nothing, _vChunks = Chunks (Numeric 8 :| [Numeric 10,Numeric 7]), _vRel = Nothing, _vMeta = Nothing}}-    ghc948rc2 = GHCTargetVersion {_tvTarget = Nothing, _tvVersion = Version {_vEpoch = Nothing, _vChunks = Chunks (Numeric 9 :| [Numeric 4,Numeric 8]), _vRel = Just (Release (Alphanum "rc2" :| [])), _vMeta = Nothing}}-    ghcMytag = GHCTargetVersion {_tvTarget = Nothing, _tvVersion = Version {_vEpoch = Nothing, _vChunks = Chunks (Alphanum "mytag9" :| [Numeric 4,Numeric 8]), _vRel = Nothing, _vMeta = Nothing}}-    ghcjs962 = GHCTargetVersion {_tvTarget = Just "javascript-unknown-ghcjs", _tvVersion = Version { _vEpoch = Nothing, _vChunks = Chunks (Numeric 9 :| [Numeric 6,Numeric 2]), _vRel = Nothing, _vMeta = Nothing}}+    hls2_13_0_0 = Right TargetVersion {+                   _tvTarget = Nothing,+                   _tvVersion = Version {+                     _vEpoch = Nothing,+                     _vChunks = Chunks (Numeric 2 :| [Numeric 13, Numeric 0, Numeric 0]),+                     _vRel = Nothing,+                     _vMeta = Nothing+                   }+                 }+    cabal_3_14_1_0 = Right TargetVersion {+                   _tvTarget = Nothing,+                   _tvVersion = Version {+                     _vEpoch = Nothing,+                     _vChunks = Chunks (Numeric 3 :| [Numeric 14, Numeric 1, Numeric 0]),+                     _vRel = Nothing,+                     _vMeta = Nothing+                   }+                 }+    ghc8107 = TargetVersion {_tvTarget = Nothing, _tvVersion = Version {_vEpoch = Nothing, _vChunks = Chunks (Numeric 8 :| [Numeric 10,Numeric 7]), _vRel = Nothing, _vMeta = Nothing}}+    ghc948rc2 = TargetVersion {_tvTarget = Nothing, _tvVersion = Version {_vEpoch = Nothing, _vChunks = Chunks (Numeric 9 :| [Numeric 4,Numeric 8]), _vRel = Just (Release (Alphanum "rc2" :| [])), _vMeta = Nothing}}+    ghcMytag = TargetVersion {_tvTarget = Nothing, _tvVersion = Version {_vEpoch = Nothing, _vChunks = Chunks (Alphanum "mytag9" :| [Numeric 4,Numeric 8]), _vRel = Nothing, _vMeta = Nothing}}+    ghcjs962 = TargetVersion {_tvTarget = Just "javascript-unknown-ghcjs", _tvVersion = Version { _vEpoch = Nothing, _vChunks = Chunks (Numeric 9 :| [Numeric 6,Numeric 2]), _vRel = Nothing, _vMeta = Nothing}}
test/ghcup-test/GHCup/Prelude/File/Posix/TraversalsSpec.hs view
@@ -8,7 +8,6 @@  import           Control.Monad.IO.Class (liftIO) import           Data.List-import           System.Posix.Directory import           Unsafe.Coerce #endif 
test/ghcup-test/GHCup/Types/JSONSpec.hs view
@@ -1,21 +1,127 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE TypeApplications #-}  module GHCup.Types.JSONSpec where -import           GHCup.ArbitraryTypes ()-import           GHCup.Types hiding ( defaultSettings )-import           GHCup.Types.JSON ()-import           GHCup.Prelude+import GHCup.ArbitraryTypes ()+import GHCup.Prelude+import GHCup.Types hiding ( defaultSettings )+import GHCup.Types.Dhall ()+import GHCup.Types.JSON () -import           Control.Monad (when)-import           Test.Aeson.GenericSpecs-import           Test.Hspec+import Control.Monad (when, forM_)+import System.FilePath+import Test.Aeson.GenericSpecs+import Test.Hspec.Golden+import Test.Hspec +import qualified Data.Text as T+import qualified Data.Text.IO as T+import qualified Data.Aeson.Encode.Pretty as Aeson+import qualified Data.Yaml as YAML +#if defined(DHALL)+import Dhall.Marshal.Encode ()+import qualified Dhall.Core as Dhall+import qualified Dhall.Binary as Dhall+import qualified Dhall hiding (Text)+import qualified Data.Void as V+import Dhall.Yaml (dhallToYaml, defaultOptions)+import Dhall.JSON (convertToHomogeneousMaps, Conversion(..))+#endif  spec :: Spec spec = do   roundtripSpecs (Proxy @LinuxDistro)+  roundtripSpecs (Proxy @EnvSpec)+  roundtripSpecs (Proxy @ConfigSpec)+  roundtripSpecs (Proxy @MakeSpec)+  roundtripSpecs (Proxy @SymlinkInputSpec)+  roundtripSpecs (Proxy @InstallationSpecInput)+  roundtripSpecs (Proxy @Tool)+  roundtripSpecs (Proxy @TargetVersion)+  roundtripSpecs (Proxy @VersionInfo)+  roundtripSpecs (Proxy @Architecture)+  roundtripSpecs (Proxy @Platform)+  roundtripSpecs (Proxy @VersionRange)+  roundtripSpecs (Proxy @URLSource)+  roundtripSpecs (Proxy @UserSettings)+  roundtripSpecs (Proxy @GHCupDownloads)+  roundtripSpecs (Proxy @ToolInfo)+  roundtripSpecs (Proxy @ToolDescription)+  roundtripSpecs (Proxy @ToolVersionSpec)+  roundtripSpecs (Proxy @VersionMetadata)+  roundtripSpecs (Proxy @RevisionSpec)+  roundtripSpecs (Proxy @VersionInfo)+  roundtripSpecs (Proxy @ArchitectureSpec)+  roundtripSpecs (Proxy @PlatformSpec)+  roundtripSpecs (Proxy @PlatformVersionSpec)+  roundtripSpecs (Proxy @DownloadInfo)+  roundtripSpecs (Proxy @GHCupInfo)+#if !defined(i386_HOST_ARCH)   when (not isWindows) $     roundtripAndGoldenSpecsWithSettings (defaultSettings { goldenDirectoryOption = CustomDirectoryName "test/ghcup-test/golden/unix", sampleSize = 2 }) (Proxy @GHCupInfo)+#endif +  describe "Parse old metadata" $ do+    forM_ yamls $ \v ->+      it v $ do+        (Right info) <- YAML.decodeFileEither @GHCupInfo $ "data/test/ghcup-" <> v+        pure $ Golden {+             output = decUTF8Safe' $ Aeson.encodePretty info+           , encodePretty = T.unpack+           , writeToFile = T.writeFile+           , readFromFile = T.readFile+           , goldenFile = "test/ghcup-test/golden/old_metadata/ghcup-" <> dropExtension v+           , actualFile = Nothing+           , failFirstTime = False+           }++#if defined(DHALL)+  describe "Dhall roundtrip" $ do+    beforeAll (do+        info <- YAML.decodeFileEither @GHCupInfo "data/test/ghcup-0.1.0.yaml" >>= either (fail . show) pure+        let expr = Dhall.denote $ Dhall.embed @GHCupInfo Dhall.inject info+        pure (info, expr)+      ) $ do+          it "Normal dhall" $ \(info, expr) -> do+            nInfo <- roundTripNormal expr+            nInfo `shouldBe` info+          it "Binary dhall" $ \(info, expr) -> do+            bInfo <- roundTripBinary expr+            bInfo `shouldBe` info+          it "dhall-to-yaml" $ \(info, expr) -> do+            yInfo <- roundTripYaml expr+            yInfo `shouldBe` info+#endif+ where+  yamls = [ "0.0.1.json"+          , "0.0.2.json"+          , "0.0.3.yaml"+          , "0.0.4.yaml"+          , "0.0.5.yaml"+          , "0.0.6.yaml"+          , "0.0.7.yaml"+          , "0.0.8.yaml"+          , "0.0.9.yaml"+          , "0.1.0.yaml"+          ]+#if defined(DHALL)+  roundTripNormal :: Dhall.Expr V.Void V.Void -> IO GHCupInfo+  roundTripNormal expr = do+    let dhallCode = Dhall.pretty expr+    Dhall.input @GHCupInfo Dhall.auto dhallCode++  roundTripBinary :: Dhall.Expr V.Void V.Void -> IO GHCupInfo+  roundTripBinary expr = do+    let dhallCode = Dhall.encodeExpression expr+    expr' <- either (fail . show) pure $ Dhall.decodeExpression @V.Void @V.Void dhallCode+    Dhall.rawInput Dhall.auto expr'++  -- using dhall-to-yaml essentially+  roundTripYaml :: Dhall.Expr V.Void V.Void -> IO GHCupInfo+  roundTripYaml (convertToHomogeneousMaps NoConversion -> expr) = do+    let dhallCode = Dhall.pretty expr+    yaml <- dhallToYaml defaultOptions Nothing dhallCode+    either (fail . show) pure $ YAML.decodeEither' yaml+#endif
test/ghcup-test/golden/unix/GHCupInfo.json view
@@ -2,13743 +2,2460 @@     "samples": [         {             "ghcupDownloads": {-                "Cabal": {-                    "1.1.8": {-                        "viArch": {-                            "A_ARM": {-                                "FreeBSD": {-                                    "unknown_versioning": {-                                        "dlCSize": -4,-                                        "dlHash": "lzmi",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:vedinez"-                                    }-                                }-                            },-                            "A_PowerPC": {-                                "Darwin": {-                                    "( < 3.4.1 && < 1.2.2 && >= 2.4.5 && >= 1.1.4 && > 4.1.2 )": {-                                        "dlCSize": -2,-                                        "dlHash": "dqlsply",-                                        "dlOutput": "KS𡅫➲􋛌>\u0002",-                                        "dlSubdir": {-                                            "RegexDir": "I\u0004"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "LatestPrerelease",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:heaonl"-                                    },-                                    "( < 4.5.3 && == 2.3.1 && <= 1.2.3 ) || ( > 3.1.1 && > 1.1.1 && < 3.4.3 && <= 1.4.1 && <= 1.5.1 )": {-                                        "dlCSize": 3,-                                        "dlHash": "p",-                                        "dlOutput": "X9峚𰃜",-                                        "dlSubdir": "󵩪\u0014\u0015",-                                        "dlTag": null,-                                        "dlUri": "https:lpbi"-                                    },-                                    "( >= 5.5.3 && > 3.1.1 && >= 1.1.1 && > 3.5.2 && > 3.1.2 && > 5.5.4 && == 5.2.5 ) || ( == 4.2.3 && < 1.3.4 && < 3.1.2 )": {-                                        "dlCSize": -2,-                                        "dlHash": "tnhzuv",-                                        "dlOutput": "9\u0011\u0013;",-                                        "dlSubdir": {-                                            "RegexDir": "\u000f\r\u0013"-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "Latest",-                                            "base-2.3.3",-                                            "base-4.2.5",-                                            "base-5.5.6"-                                        ],-                                        "dlUri": "https:x"-                                    }-                                },-                                "FreeBSD": {-                                    "( <= 4.1.1 && >= 5.5.5 )": {-                                        "dlCSize": -2,-                                        "dlHash": "cc",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "0"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:ooueot"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -6,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Experimental",-                                            "base-2.6.4",-                                            "LatestPrerelease",-                                            "base-3.5.4",-                                            "old",-                                            "Prerelease",-                                            "D\u000ba"-                                        ],-                                        "dlUri": "https:ghaoqgd"-                                    }-                                },-                                "Linux_Fedora": {-                                    "( < 4.3.4 && >= 4.2.1 && > 2.4.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "zjbzn",-                                        "dlOutput": "%",-                                        "dlSubdir": {-                                            "RegexDir": "H"-                                        },-                                        "dlTag": [-                                            "base-5.4.1"-                                        ],-                                        "dlUri": "https:atcokx"-                                    },-                                    "( <= 3.5.1 && == 2.4.4 && > 4.1.5 && <= 3.5.4 && <= 2.3.5 )": {-                                        "dlCSize": -3,-                                        "dlHash": "dymxs",-                                        "dlOutput": null,-                                        "dlSubdir": "k",-                                        "dlTag": [-                                            "LatestNightly",-                                            "LatestPrerelease",-                                            "LatestNightly",-                                            "Experimental",-                                            "base-3.4.3",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:gki"-                                    },-                                    "( > 4.5.3 && < 5.5.3 && == 4.3.4 && >= 1.3.5 && == 1.3.2 && == 2.4.2 && <= 4.4.2 ) || ( >= 2.3.1 )": {-                                        "dlCSize": -6,-                                        "dlHash": "hco",-                                        "dlOutput": "e&",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "LatestPrerelease",-                                            "LatestPrerelease",-                                            "Latest",-                                            "Recommended",-                                            "LatestPrerelease",-                                            "􏕲"-                                        ],-                                        "dlUri": "https:trqoj"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 6,-                                        "dlHash": "vbx",-                                        "dlOutput": "𲇀蚗\u0014%\u001d󼅚",-                                        "dlSubdir": {-                                            "RegexDir": ";H󶶽𩹽Ὗ"-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:a"-                                    }-                                }-                            },-                            "A_Sparc": {-                                "Darwin": {-                                    "( < 5.2.3 && <= 5.4.5 && < 1.3.5 && >= 5.1.5 && <= 1.4.1 ) || ( <= 4.2.4 && < 4.4.3 && == 1.3.2 && >= 3.3.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "j",-                                        "dlOutput": null,-                                        "dlSubdir": "3󱦶",-                                        "dlTag": [-                                            "base-6.2.2",-                                            "Latest",-                                            "J𫵥{>p𦐬",-                                            "base-5.6.1",-                                            "Latest",-                                            "Recommended",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:ajaluz"-                                    },-                                    "( == 1.3.5 && >= 3.5.1 && < 5.2.4 && <= 3.2.4 && <= 5.5.1 && < 4.4.2 && <= 1.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "yyala",-                                        "dlOutput": "\u0018𔑑󱚋0m",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:"-                                    },-                                    "( > 1.1.1 && >= 5.3.1 && > 2.5.5 && <= 5.4.2 && > 1.4.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "abr",-                                        "dlOutput": "I\u001e",-                                        "dlSubdir": "",-                                        "dlTag": null,-                                        "dlUri": "https:kbhpcd"-                                    },-                                    "( > 1.1.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "tkevrp",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Experimental",-                                            "old"-                                        ],-                                        "dlUri": "https:hqkbim"-                                    },-                                    "( > 1.1.3 ) || ( >= 1.1.4 )": {-                                        "dlCSize": -7,-                                        "dlHash": "lqyavl",-                                        "dlOutput": "Si6\tD$",-                                        "dlSubdir": {-                                            "RegexDir": "`0"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "Experimental",-                                            "base-5.3.4",-                                            "base-6.6.2"-                                        ],-                                        "dlUri": "https:q"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 3,-                                        "dlHash": "ep",-                                        "dlOutput": "mX",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease",-                                            "LatestPrerelease",-                                            "Experimental",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:m"-                                    }-                                },-                                "Linux_CentOS": {-                                    "( < 5.4.2 && >= 1.4.1 && >= 1.4.3 && > 5.2.3 && < 3.2.4 )": {-                                        "dlCSize": -4,-                                        "dlHash": "s",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease",-                                            ""-                                        ],-                                        "dlUri": "http:pntmrxm"-                                    },-                                    "( == 1.2.2 ) || ( > 1.2.1 && <= 2.1.4 && >= 4.3.2 && > 1.2.3 && > 2.3.4 && == 4.5.1 ) || ( <= 1.1.1 && > 1.1.1 && == 2.2.2 )": {-                                        "dlCSize": -3,-                                        "dlHash": "i",-                                        "dlOutput": "EG\u0000",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:sso"-                                    },-                                    "( == 4.3.2 )": {-                                        "dlCSize": -7,-                                        "dlHash": "",-                                        "dlOutput": "\u0000w[97J",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [],-                                        "dlUri": "http:nlxuse"-                                    }-                                },-                                "Linux_UnknownLinux": {-                                    "( < 3.4.2 )": {-                                        "dlCSize": 7,-                                        "dlHash": "xbwtnq",-                                        "dlOutput": "\t󸢣v",-                                        "dlSubdir": "[v",-                                        "dlTag": null,-                                        "dlUri": "https:"-                                    },-                                    "( <= 2.2.3 && <= 3.4.3 && > 2.4.3 && >= 5.5.2 && <= 2.4.1 && > 1.2.4 ) || ( <= 2.2.1 && == 1.2.3 && == 4.1.4 && == 1.3.3 )": {-                                        "dlCSize": 1,-                                        "dlHash": "d",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:saw"-                                    },-                                    "( == 2.1.4 && < 4.1.2 && > 4.1.2 ) || ( == 4.3.4 && >= 1.2.3 && == 2.1.2 ) || ( >= 3.2.4 && < 1.1.3 && == 2.3.3 && >= 3.3.3 && == 1.2.3 )": {-                                        "dlCSize": -1,-                                        "dlHash": "eftchm",-                                        "dlOutput": "𢳀B󿤓",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:"-                                    },-                                    "( > 1.5.3 )": {-                                        "dlCSize": -4,-                                        "dlHash": "gkaf",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "弬x𧚭"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "LatestNightly",-                                            "LatestPrerelease",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:xajbj"-                                    },-                                    "( > 6.4.3 && == 3.5.1 && > 3.5.4 ) || ( == 3.4.1 && >= 4.3.1 && >= 4.4.4 )": {-                                        "dlCSize": 2,-                                        "dlHash": "",-                                        "dlOutput": "4k#𩾝\u0016\u001b",-                                        "dlSubdir": "O𤑼\u000e",-                                        "dlTag": [-                                            "Nightly",-                                            "Nightly",-                                            "LatestPrerelease",-                                            "Experimental",-                                            "<\u0001󴛫\u0000􇏚",-                                            "Nightly",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:qswke"-                                    },-                                    "( >= 3.2.4 ) || ( <= 1.1.2 && > 4.4.4 && == 3.2.4 && >= 3.4.1 && < 2.2.3 ) || ( < 2.3.1 && < 1.4.2 && <= 2.2.2 && > 3.3.3 )": {-                                        "dlCSize": 6,-                                        "dlHash": "vknsso",-                                        "dlOutput": "\u0010􊂔󼚙@󿏮/<",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:eetgom"-                                    },-                                    "( >= 4.4.2 && > 5.1.2 && > 5.4.1 && <= 1.1.1 ) || ( > 4.1.1 && == 2.4.3 && == 1.2.3 )": {-                                        "dlCSize": 0,-                                        "dlHash": "trvzcm",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "SF\u001dS^\u0015"-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:bgkwzu"-                                    }-                                },-                                "Windows": {-                                    "( == 4.4.3 && > 2.5.3 )": {-                                        "dlCSize": -7,-                                        "dlHash": "lsjekp",-                                        "dlOutput": null,-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "Nightly",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 0,-                                        "dlHash": "",-                                        "dlOutput": "Vu𘖖N",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "Latest",-                                            "Recommended",-                                            "Experimental",-                                            "Z󱥪"-                                        ],-                                        "dlUri": "https:irvd"-                                    }-                                }-                            }-                        },-                        "viChangeLog": null,-                        "viPostInstall": "ts",-                        "viPostRemove": "aadsa",-                        "viPreCompile": "sjpv",-                        "viPreInstall": "xvajrnk",-                        "viReleaseDay": "-21913023041306456-05-31",-                        "viSourceDL": null,-                        "viTags": [-                            "old",-                            "q-*\u0004",-                            "Nightly",-                            "base-1.6.2",-                            "old",-                            "Experimental"-                        ],-                        "viTestDL": {-                            "dlCSize": 0,-                            "dlHash": "xpegi",-                            "dlOutput": "",-                            "dlSubdir": "jR",-                            "dlTag": [-                                "Latest",-                                "LatestPrerelease",-                                "old",-                                "old",-                                "Nightly",-                                "Recommended"-                            ],-                            "dlUri": "http:h"-                        }-                    },-                    "1.3.1": {-                        "viArch": {-                            "A_ARM64": {-                                "Darwin": {-                                    "( < 4.1.4 && > 3.2.1 && >= 4.2.3 && < 3.2.5 && <= 1.2.4 && <= 5.4.5 )": {-                                        "dlCSize": 1,-                                        "dlHash": "yv",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "􂝷t\u0002砡~&"-                                        },-                                        "dlTag": [-                                            "Recommended",-                                            "old",-                                            "\u000c",-                                            "old"-                                        ],-                                        "dlUri": "http:tekt"-                                    },-                                    "( == 2.2.5 && == 2.5.1 && > 2.2.2 && < 4.2.2 && > 3.5.1 && <= 4.4.2 && >= 1.3.1 ) || ( >= 1.3.2 && < 1.2.4 && >= 1.2.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "f",-                                        "dlOutput": "f8U",-                                        "dlSubdir": "v",-                                        "dlTag": [-                                            "Prerelease",-                                            "old",-                                            "LatestNightly",-                                            "LatestNightly",-                                            "LatestNightly",-                                            ""-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( == 5.1.2 && == 1.5.1 && <= 2.5.4 && >= 4.4.3 && >= 3.6.1 && >= 2.4.1 && < 4.3.2 )": {-                                        "dlCSize": 7,-                                        "dlHash": "lkvv",-                                        "dlOutput": "􌇘",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Recommended",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:en"-                                    },-                                    "( > 3.3.1 && < 6.4.2 && == 3.2.2 && < 2.3.2 ) || ( <= 3.3.3 && > 1.3.1 && == 1.3.2 && >= 2.4.3 ) || ( == 3.2.3 && >= 1.3.2 && <= 3.4.1 && >= 2.3.1 )": {-                                        "dlCSize": -4,-                                        "dlHash": "rw",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [],-                                        "dlUri": "http:vqc"-                                    },-                                    "( > 5.4.2 && <= 6.4.2 && > 1.5.5 && == 5.4.5 && < 5.4.3 && > 2.5.5 ) || ( > 4.1.3 && <= 1.2.1 && == 4.1.4 && == 3.2.3 && > 1.1.3 && <= 4.2.2 ) || ( >= 3.3.3 ) || ( == 1.2.2 )": {-                                        "dlCSize": -1,-                                        "dlHash": "tk",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "LatestPrerelease",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:gntqhy"-                                    },-                                    "( >= 4.5.2 && > 5.3.2 && < 4.2.3 && < 3.2.1 && > 3.3.6 && > 3.2.4 ) || ( < 2.1.2 )": {-                                        "dlCSize": -2,-                                        "dlHash": "lopa",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "*|\u001d"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:"-                                    },-                                    "( >= 5.1.4 && > 4.3.5 && <= 4.5.3 && <= 2.2.2 && >= 3.2.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "zw",-                                        "dlOutput": null,-                                        "dlSubdir": "G=\u001a",-                                        "dlTag": [],-                                        "dlUri": "https:ssoeizq"-                                    }-                                },-                                "FreeBSD": {-                                    "( > 3.1.3 && < 1.5.2 && <= 1.3.4 )": {-                                        "dlCSize": -6,-                                        "dlHash": "chngbv",-                                        "dlOutput": "aV𝛼%",-                                        "dlSubdir": "\u000c󳄂",-                                        "dlTag": [-                                            "Recommended",-                                            "Experimental",-                                            "Prerelease",-                                            "Latest",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:jzpusg"-                                    },-                                    "( > 4.2.5 && >= 4.2.1 )": {-                                        "dlCSize": -5,-                                        "dlHash": "lrgzgth",-                                        "dlOutput": "[\u0019􀀹\u0008r",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 3,-                                        "dlHash": "u",-                                        "dlOutput": "@\u001eOX􋦗}",-                                        "dlSubdir": "󰱪+h",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Nightly",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:omjgcyi"-                                    }-                                },-                                "Linux_AmazonLinux": {-                                    "( <= 2.3.4 )": {-                                        "dlCSize": 0,-                                        "dlHash": "hothb",-                                        "dlOutput": "D]\u0008􊐈*\u0014",-                                        "dlSubdir": "D\u0003􆥶\u0012O#",-                                        "dlTag": [-                                            "Recommended",-                                            "Recommended",-                                            "Recommended",-                                            "Prerelease",-                                            "LatestNightly",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:yv"-                                    },-                                    "( == 2.1.1 && < 4.2.2 ) || ( < 2.3.1 )": {-                                        "dlCSize": 5,-                                        "dlHash": "nw",-                                        "dlOutput": null,-                                        "dlSubdir": "󲤇Q󿉐\u0006\\F",-                                        "dlTag": [-                                            "%𤰙Y4T",-                                            "Prerelease",-                                            "old",-                                            "Nightly",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "( == 2.6.5 && == 3.1.5 && > 1.3.1 && < 2.3.3 )": {-                                        "dlCSize": 1,-                                        "dlHash": "",-                                        "dlOutput": "\u001az􈉑󿣴9𰋒N",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:jxecej"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "iqvf",-                                        "dlOutput": "\t5i",-                                        "dlSubdir": "\u0016x􋄈",-                                        "dlTag": [-                                            "base-5.1.3",-                                            "Latest",-                                            "LatestPrerelease",-                                            "Prerelease",-                                            "old"-                                        ],-                                        "dlUri": "https:r"-                                    }-                                },-                                "Linux_Mint": {-                                    "( < 5.4.1 ) || ( <= 3.2.4 )": {-                                        "dlCSize": -3,-                                        "dlHash": "",-                                        "dlOutput": "d$",-                                        "dlSubdir": {-                                            "RegexDir": "󱼸􃇣𗿦u6"-                                        },-                                        "dlTag": [-                                            "Latest",-                                            "base-3.2.2",-                                            "LatestPrerelease",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:ouccox"-                                    },-                                    "( <= 5.3.1 && == 1.3.3 && == 2.1.2 ) || ( > 2.4.2 && == 1.3.2 && > 4.5.1 && == 4.3.2 ) || ( >= 2.2.2 && >= 3.2.1 && >= 2.3.2 ) || ( >= 2.2.2 && == 3.2.1 )": {-                                        "dlCSize": 7,-                                        "dlHash": "",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:htumd"-                                    },-                                    "( > 1.5.3 && < 2.5.5 && < 3.1.5 && > 4.1.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "kxeomhq",-                                        "dlOutput": "𩼲",-                                        "dlSubdir": {-                                            "RegexDir": "|C𫾝􈸘􍏖S"-                                        },-                                        "dlTag": [-                                            "Nightly"-                                        ],-                                        "dlUri": "https:trnup"-                                    },-                                    "( >= 2.2.1 && < 5.1.2 && > 2.5.2 && >= 4.3.5 && >= 5.3.5 ) || ( > 3.3.2 && >= 3.1.3 && < 3.2.2 && < 4.3.2 && == 2.3.3 && < 3.1.1 )": {-                                        "dlCSize": 3,-                                        "dlHash": "rsrml",-                                        "dlOutput": "",-                                        "dlSubdir": "D*􋨾􁦰T",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "LatestPrerelease",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:abymyoi"-                                    },-                                    "( >= 6.4.2 && <= 2.2.5 && < 5.5.1 && == 3.1.5 ) || ( <= 2.3.3 && >= 2.2.2 && > 3.1.3 ) || ( >= 1.2.2 && < 3.2.2 )": {-                                        "dlCSize": 0,-                                        "dlHash": "bfyobhv",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "old",-                                            "",-                                            "LatestNightly",-                                            "Nightly",-                                            "old",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:idvu"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -3,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": " \u0000y",-                                        "dlTag": [-                                            "base-6.5.4"-                                        ],-                                        "dlUri": "http:hh"-                                    }-                                },-                                "Linux_RedHat": {-                                    "( < 3.2.1 && >= 2.1.2 && > 1.6.5 && >= 3.4.4 && == 1.5.1 && > 4.1.1 )": {-                                        "dlCSize": -5,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "𩃀UR𮆽"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Latest",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:wqvr"-                                    },-                                    "( == 1.2.2 && <= 1.1.1 ) || ( <= 2.1.4 && >= 2.2.5 && < 4.1.1 && < 3.1.5 )": {-                                        "dlCSize": 3,-                                        "dlHash": "",-                                        "dlOutput": "#5󹨚㨄$",-                                        "dlSubdir": "hWB􅇇",-                                        "dlTag": [-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:uvvym"-                                    },-                                    "( > 1.4.2 && >= 5.4.2 && > 5.1.3 && >= 1.5.4 && >= 3.3.4 && < 2.2.4 && == 3.3.3 ) || ( < 3.2.3 && == 1.1.3 && >= 5.3.4 )": {-                                        "dlCSize": 5,-                                        "dlHash": "jtozy",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:ooqmx"-                                    },-                                    "( >= 5.2.4 && >= 2.6.2 ) || ( > 2.2.2 && <= 2.3.1 ) || ( < 3.3.2 && >= 2.3.2 && < 2.3.1 && > 1.2.3 && < 2.3.1 ) || ( <= 2.1.2 && > 1.1.1 ) || ( >= 1.1.1 && < 1.1.1 ) || ( <= 1.2.1 ) || ( <= 1.1.1 ) || ( > 1.1.1 )": {-                                        "dlCSize": -1,-                                        "dlHash": "",-                                        "dlOutput": "\u0018I\u001a󲾗",-                                        "dlSubdir": {-                                            "RegexDir": "xd"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:"-                                    },-                                    "( >= 5.4.4 && <= 2.4.1 && > 3.5.5 )": {-                                        "dlCSize": 2,-                                        "dlHash": "k",-                                        "dlOutput": "攤>\u0001X<実",-                                        "dlSubdir": "Y\u000c",-                                        "dlTag": [],-                                        "dlUri": "http:aet"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -1,-                                        "dlHash": "mias",-                                        "dlOutput": ".𪕡PO",-                                        "dlSubdir": {-                                            "RegexDir": "􉦒\u00127J"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:xgqvaxv"-                                    }-                                },-                                "Windows": {-                                    "( < 1.1.1 && <= 4.4.5 && <= 3.2.5 && <= 4.4.5 && < 2.1.4 && <= 2.3.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "liccth",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "`,'q"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "Recommended",-                                            "Latest",-                                            "base-4.6.3"-                                        ],-                                        "dlUri": "http:cr"-                                    },-                                    "( < 3.3.5 && <= 1.1.5 && >= 5.1.2 ) || ( == 4.4.4 && <= 2.2.4 && == 4.1.1 && <= 3.2.1 )": {-                                        "dlCSize": 7,-                                        "dlHash": "azlzsuh",-                                        "dlOutput": null,-                                        "dlSubdir": "NES\u001f",-                                        "dlTag": null,-                                        "dlUri": "http:x"-                                    },-                                    "( == 3.5.4 && > 3.4.3 && < 2.2.3 && <= 3.5.5 && <= 1.4.2 && == 2.2.2 )": {-                                        "dlCSize": 3,-                                        "dlHash": "fklgn",-                                        "dlOutput": "􍑾𥮏=M",-                                        "dlSubdir": {-                                            "RegexDir": "\u0000\"!QR􁙲"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:bdplzf"-                                    },-                                    "( == 5.5.2 && > 1.1.5 && <= 4.1.4 && == 5.1.2 && < 3.2.5 ) || ( <= 2.4.4 && < 1.3.1 && >= 3.2.1 && >= 1.2.4 ) || ( == 1.3.1 && > 1.2.2 && == 2.3.1 && >= 3.2.1 )": {-                                        "dlCSize": -2,-                                        "dlHash": "",-                                        "dlOutput": "󹌑Z𠔖 􁢞\u000b􊙂",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "base-2.6.3",-                                            "Recommended",-                                            "old",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:zlmmza"-                                    },-                                    "( > 4.5.5 && <= 1.5.3 ) || ( >= 1.2.4 && < 2.4.3 )": {-                                        "dlCSize": -5,-                                        "dlHash": "rvgzqha",-                                        "dlOutput": null,-                                        "dlSubdir": "1}",-                                        "dlTag": [-                                            "Prerelease",-                                            "LatestNightly",-                                            "Prerelease",-                                            "ɜjz",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:z"-                                    },-                                    "( >= 3.3.4 ) || ( == 3.2.2 && < 2.1.1 && == 4.3.3 )": {-                                        "dlCSize": 6,-                                        "dlHash": "plhh",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "\u001a"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 7,-                                        "dlHash": "ymisz",-                                        "dlOutput": null,-                                        "dlSubdir": "J2𰿤",-                                        "dlTag": [-                                            "old",-                                            "y \u0007󹁄\u001f",-                                            "Nightly",-                                            "Latest",-                                            "Prerelease",-                                            "LatestPrerelease",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:vw"-                                    }-                                }-                            }-                        },-                        "viChangeLog": "https:rjtn",-                        "viPostInstall": "pckwp",-                        "viPostRemove": "t",-                        "viPreCompile": null,-                        "viPreInstall": "amr",-                        "viReleaseDay": "-24610868170639988-07-05",-                        "viSourceDL": {-                            "dlCSize": -6,-                            "dlHash": "zlk",-                            "dlOutput": null,-                            "dlSubdir": null,-                            "dlTag": [],-                            "dlUri": "https:uvyxt"-                        },-                        "viTags": [-                            "old",-                            "old",-                            "Prerelease",-                            "",-                            "base-5.4.1",-                            "Experimental"-                        ],-                        "viTestDL": {-                            "dlCSize": null,-                            "dlHash": "mrw",-                            "dlOutput": "|\u0000,",-                            "dlSubdir": "\u00113󾽨𧌛",-                            "dlTag": [-                                "LatestNightly",-                                "1Y󵝡_"-                            ],-                            "dlUri": "https:virs"-                        }-                    },-                    "4.2.1": {-                        "viArch": {-                            "A_32": {-                                "FreeBSD": {-                                    "( < 5.2.2 && >= 2.4.5 ) || ( < 3.2.4 )": {-                                        "dlCSize": 4,-                                        "dlHash": "qqf",-                                        "dlOutput": null,-                                        "dlSubdir": "5Oc",-                                        "dlTag": [-                                            "Nightly",-                                            "Latest"-                                        ],-                                        "dlUri": "http:jtbr"-                                    },-                                    "( == 3.1.5 )": {-                                        "dlCSize": 2,-                                        "dlHash": "uyitmss",-                                        "dlOutput": "]",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Experimental",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:bqm"-                                    },-                                    "( == 5.5.5 && == 4.4.2 && > 1.3.2 && >= 3.5.5 && > 3.5.1 && > 1.1.5 )": {-                                        "dlCSize": 6,-                                        "dlHash": "",-                                        "dlOutput": "󴪥󽤸m\u000cIJ\u000c",-                                        "dlSubdir": "𭬺􎈷",-                                        "dlTag": [-                                            "\u001arBK",-                                            "Bnq",-                                            "Experimental",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:zdqt"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 0,-                                        "dlHash": "eolkn",-                                        "dlOutput": "n\u001d&",-                                        "dlSubdir": "PnJ",-                                        "dlTag": null,-                                        "dlUri": "https:"-                                    }-                                }-                            },-                            "A_ARM": {},-                            "A_ARM64": {-                                "Linux_Alpine": {-                                    "( < 1.5.4 && >= 1.2.5 && == 1.5.3 && == 3.3.2 ) || ( >= 1.2.4 && == 5.3.1 && == 1.3.2 && > 3.2.4 && == 4.2.2 && == 3.1.2 ) || ( >= 4.1.3 && >= 2.4.1 && <= 2.1.1 && > 2.3.2 && < 1.2.3 ) || ( < 3.1.2 && == 2.1.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "ozx",-                                        "dlOutput": "\u001fEv",-                                        "dlSubdir": {-                                            "RegexDir": "ꋑ㏄TA"-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:n"-                                    },-                                    "( == 3.5.3 && <= 3.4.3 && <= 3.1.1 && == 3.5.2 ) || ( == 3.2.1 && > 2.3.1 && > 3.3.1 && == 4.1.4 && > 1.4.3 ) || ( == 1.3.1 )": {-                                        "dlCSize": -4,-                                        "dlHash": "gtdl",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "\u0001u􎥱\u001b"-                                        },-                                        "dlTag": [-                                            "old",-                                            "base-5.2.2",-                                            "",-                                            "Prerelease",-                                            "LatestNightly",-                                            "Nightly",-                                            "Latest"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 0,-                                        "dlHash": "ubxrft",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "\u001b$ZWf&"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:nugrj"-                                    }-                                }-                            },-                            "A_PowerPC": {-                                "Darwin": {-                                    "( < 5.4.2 )": {-                                        "dlCSize": 2,-                                        "dlHash": "bsasg",-                                        "dlOutput": "􅧙\u001a",-                                        "dlSubdir": {-                                            "RegexDir": "OꉰuT"-                                        },-                                        "dlTag": [-                                            "Recommended",-                                            "LatestNightly",-                                            "old",-                                            "Experimental",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:h"-                                    },-                                    "( <= 4.4.2 && <= 2.4.5 ) || ( == 3.2.1 && > 3.1.1 && < 2.4.2 ) || ( <= 1.3.3 )": {-                                        "dlCSize": 2,-                                        "dlHash": "cbzdk",-                                        "dlOutput": "𪣸줿\t󶀍s",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:ewdmm"-                                    },-                                    "( > 2.2.3 && > 4.3.5 && < 1.1.3 && == 5.1.3 && == 3.5.1 && < 5.2.5 ) || ( < 3.3.3 && >= 3.3.3 ) || ( > 1.2.1 && <= 3.1.2 && >= 2.3.2 && > 3.2.3 && >= 2.2.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "vlkxrw",-                                        "dlOutput": "R\u0005Xo\u000c",-                                        "dlSubdir": {-                                            "RegexDir": "9"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:iuy"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -6,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:d"-                                    }-                                },-                                "FreeBSD": {-                                    "( <= 2.5.3 )": {-                                        "dlCSize": 0,-                                        "dlHash": "zdknvdb",-                                        "dlOutput": "U𨮺󷭞\u0006O,Y",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:p"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 2,-                                        "dlHash": "glvod",-                                        "dlOutput": "Z\" ",-                                        "dlSubdir": "q",-                                        "dlTag": [-                                            "LatestNightly",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:jowrkid"-                                    }-                                },-                                "Linux_Debian": {-                                    "( < 1.2.2 && == 4.1.1 && <= 3.6.3 && <= 4.3.3 && > 5.5.3 && > 5.5.2 ) || ( <= 3.2.1 && >= 4.2.3 ) || ( <= 1.3.3 && < 1.3.2 && == 1.2.1 )": {-                                        "dlCSize": 0,-                                        "dlHash": "otyr",-                                        "dlOutput": "AfO",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Experimental",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:gutfwqk"-                                    },-                                    "( == 3.4.2 )": {-                                        "dlCSize": -3,-                                        "dlHash": "b",-                                        "dlOutput": "7\u0006*\u0003",-                                        "dlSubdir": {-                                            "RegexDir": "(Y鞌󴛃뿊|"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:q"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 7,-                                        "dlHash": "h",-                                        "dlOutput": ",􆿒",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:vzuiib"-                                    }-                                },-                                "Linux_Exherbo": {-                                    "( == 1.4.3 && == 3.4.4 && == 2.3.1 ) || ( > 1.2.3 && == 1.4.4 ) || ( == 2.1.1 ) || ( < 2.1.2 && > 1.2.2 && < 1.2.2 && < 1.2.2 )": {-                                        "dlCSize": 2,-                                        "dlHash": "wolqmja",-                                        "dlOutput": "}𐆓o",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:vc"-                                    },-                                    "( >= 3.4.4 && < 3.1.2 && >= 5.5.1 && >= 4.5.5 && >= 1.1.2 && > 5.1.4 ) || ( > 2.1.3 && >= 2.1.1 && < 2.4.3 && < 1.2.2 && <= 2.2.1 && >= 4.3.2 ) || ( < 2.3.2 )": {-                                        "dlCSize": 3,-                                        "dlHash": "zxrygc",-                                        "dlOutput": null,-                                        "dlSubdir": "~Q&\u001d􎸮",-                                        "dlTag": [-                                            "LatestNightly",-                                            "old",-                                            "Prerelease",-                                            "Recommended",-                                            "LatestNightly",-                                            "uMhH𬅫*"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 4,-                                        "dlHash": "",-                                        "dlOutput": "q𩚵㈥\n",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:ayf"-                                    }-                                },-                                "Linux_Fedora": {-                                    "( < 6.3.3 && < 2.3.2 && >= 3.5.5 ) || ( > 1.2.3 && <= 1.5.5 && == 4.2.4 && >= 2.4.1 && <= 2.4.2 )": {-                                        "dlCSize": 7,-                                        "dlHash": "s",-                                        "dlOutput": "/?>\r",-                                        "dlSubdir": "V^\n󿘒",-                                        "dlTag": [],-                                        "dlUri": "https:cb"-                                    },-                                    "( >= 5.1.5 && < 4.5.2 && >= 3.5.5 && <= 4.3.2 && < 3.2.4 ) || ( <= 2.1.1 && == 4.1.4 && == 1.3.1 && <= 2.1.1 ) || ( <= 2.3.3 && <= 3.3.3 && <= 1.2.2 && >= 1.3.2 && < 2.1.3 ) || ( < 1.1.2 && >= 1.1.2 && <= 1.1.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "qwgkh",-                                        "dlOutput": "If􅵅#=5\u000f",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [],-                                        "dlUri": "http:"-                                    }-                                },-                                "Windows": {-                                    "( > 2.1.2 ) || ( <= 2.3.3 && > 2.1.4 && <= 2.2.2 && < 4.1.1 && > 2.1.3 && < 4.3.3 )": {-                                        "dlCSize": -6,-                                        "dlHash": "psu",-                                        "dlOutput": "",-                                        "dlSubdir": "Y\u0010櫦",-                                        "dlTag": [-                                            "Latest",-                                            "old",-                                            "Latest",-                                            "LatestNightly",-                                            "Experimental",-                                            "Recommended",-                                            "base-5.3.3"-                                        ],-                                        "dlUri": "https:ysarf"-                                    },-                                    "( > 5.5.4 && == 2.3.1 && >= 5.1.5 ) || ( <= 1.4.3 ) || ( == 1.1.3 && > 3.2.1 && >= 2.2.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "(\u0010\u0017p"-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 1,-                                        "dlHash": "unvlr",-                                        "dlOutput": "\u001f󶗷",-                                        "dlSubdir": "𧋢E4$",-                                        "dlTag": [-                                            "Latest",-                                            "base-4.2.6",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:vlp"-                                    }-                                }-                            },-                            "A_PowerPC64": {-                                "FreeBSD": {},-                                "Linux_Alpine": {-                                    "( > 2.2.5 && >= 3.5.1 && <= 3.1.2 && >= 2.5.2 && <= 3.1.2 && == 4.2.4 && == 5.4.4 )": {-                                        "dlCSize": 7,-                                        "dlHash": "e",-                                        "dlOutput": "\u0018",-                                        "dlSubdir": "\u0002[",-                                        "dlTag": null,-                                        "dlUri": "http:xgkygba"-                                    }-                                },-                                "Linux_Debian": {-                                    "( <= 1.1.3 && == 4.3.4 && > 2.5.4 && > 5.4.2 && > 1.5.3 ) || ( == 2.1.1 && < 3.2.4 )": {-                                        "dlCSize": -4,-                                        "dlHash": "uxklunx",-                                        "dlOutput": "U<fo\u0008\u0000",-                                        "dlSubdir": "􅠻b𓁈k",-                                        "dlTag": [-                                            "Latest",-                                            "old",-                                            "Experimental",-                                            "Recommended",-                                            "Latest",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "r",-                                        "dlOutput": "{V\u0001%HO",-                                        "dlSubdir": "𘊆\u000c",-                                        "dlTag": null,-                                        "dlUri": "https:u"-                                    }-                                },-                                "Linux_Exherbo": {},-                                "Windows": {-                                    "( <= 1.5.2 && <= 1.5.1 && >= 2.2.3 && <= 2.2.1 && <= 7.5.2 && <= 1.1.2 )": {-                                        "dlCSize": -3,-                                        "dlHash": "",-                                        "dlOutput": "y}i\u0018w",-                                        "dlSubdir": "Q",-                                        "dlTag": [-                                            "Latest",-                                            "Latest",-                                            "Recommended",-                                            "LatestPrerelease",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:joyjye"-                                    },-                                    "( >= 1.5.5 )": {-                                        "dlCSize": 4,-                                        "dlHash": "z",-                                        "dlOutput": "c\u0016",-                                        "dlSubdir": "\u0007\u0016}𑑗2",-                                        "dlTag": null,-                                        "dlUri": "http:nevap"-                                    },-                                    "( >= 5.4.1 && >= 5.2.1 && >= 1.3.3 && <= 5.1.3 ) || ( <= 4.2.4 && > 4.2.4 && > 4.5.3 ) || ( > 3.3.1 && < 3.4.1 && <= 3.3.3 && == 2.2.2 && < 1.3.2 ) || ( > 1.2.2 && == 3.1.1 && < 1.1.2 )": {-                                        "dlCSize": -6,-                                        "dlHash": "niyotv",-                                        "dlOutput": "1𝨂o",-                                        "dlSubdir": {-                                            "RegexDir": "k"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:b"-                                    },-                                    "( >= 6.3.2 && > 3.1.5 ) || ( <= 4.3.3 && >= 4.4.2 && <= 1.3.2 )": {-                                        "dlCSize": -5,-                                        "dlHash": "j",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "Recommended"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "vt",-                                        "dlOutput": "䜔\u000b(\u0013",-                                        "dlSubdir": "\t𔕾kyG!",-                                        "dlTag": [-                                            "LatestNightly",-                                            "Latest",-                                            "Prerelease",-                                            "LatestPrerelease",-                                            "Prerelease",-                                            "old",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:czwgy"-                                    }-                                }-                            },-                            "A_Sparc64": {-                                "Darwin": {-                                    "( < 5.3.5 && >= 1.3.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "guentr",-                                        "dlOutput": "\u0008",-                                        "dlSubdir": "g)X밿>u",-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    },-                                    "( <= 1.4.1 && <= 5.1.2 && <= 4.4.2 && >= 5.3.5 && == 3.1.2 && <= 1.2.1 && > 5.3.3 ) || ( <= 3.2.3 && <= 4.1.2 && < 3.1.1 && == 3.3.2 && > 2.1.4 ) || ( > 2.2.3 && > 1.1.3 && == 1.1.1 && > 2.1.3 ) || ( < 2.2.1 ) || ( >= 1.2.2 && <= 1.1.1 ) || ( <= 1.2.1 ) || ( == 1.1.1 )": {-                                        "dlCSize": 0,-                                        "dlHash": "iqa",-                                        "dlOutput": "󲵌?𗽅",-                                        "dlSubdir": {-                                            "RegexDir": "\u001e\u0016;q"-                                        },-                                        "dlTag": [-                                            "base-6.5.3",-                                            "Latest",-                                            "Experimental",-                                            "LatestPrerelease",-                                            "?"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( <= 5.1.3 && <= 2.2.1 && > 3.4.2 )": {-                                        "dlCSize": 5,-                                        "dlHash": "hobqlar",-                                        "dlOutput": "X!\u0017X𩇊",-                                        "dlSubdir": "bZ𑆌J",-                                        "dlTag": [-                                            "Latest",-                                            ",P\u0017",-                                            "Recommended",-                                            "s𦆨M󷰫]",-                                            "Prerelease",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:lqwmz"-                                    },-                                    "( > 5.5.5 ) || ( <= 2.2.4 && < 1.3.3 && > 4.1.2 && == 2.2.4 && < 4.2.1 && == 1.4.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "tbhtnso",-                                        "dlOutput": null,-                                        "dlSubdir": "󻋞",-                                        "dlTag": [],-                                        "dlUri": "http:xkkrb"-                                    },-                                    "( >= 3.5.4 && >= 4.6.4 && >= 2.5.4 && <= 5.1.4 && <= 5.5.4 && <= 3.2.3 && < 3.5.5 ) || ( <= 4.1.3 && < 4.5.4 && <= 2.1.3 )": {-                                        "dlCSize": 5,-                                        "dlHash": "yaq",-                                        "dlOutput": "h\u001b",-                                        "dlSubdir": {-                                            "RegexDir": "if􃣿"-                                        },-                                        "dlTag": [-                                            "old",-                                            "Latest"-                                        ],-                                        "dlUri": "http:jc"-                                    },-                                    "( >= 4.1.3 && == 2.4.2 && <= 3.1.4 && >= 5.5.2 )": {-                                        "dlCSize": 2,-                                        "dlHash": "rhg",-                                        "dlOutput": "􁍷M&",-                                        "dlSubdir": "\u001b^琼􌅫",-                                        "dlTag": null,-                                        "dlUri": "http:q"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -7,-                                        "dlHash": "l",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:w"-                                    }-                                },-                                "FreeBSD": {-                                    "( < 3.5.3 && <= 5.5.4 && > 3.4.2 && == 5.3.5 && > 4.2.5 && > 1.2.3 && <= 5.4.4 )": {-                                        "dlCSize": 1,-                                        "dlHash": "ma",-                                        "dlOutput": "􇉤WF",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestNightly",-                                            "Nightly",-                                            "Latest",-                                            "Experimental",-                                            "Latest",-                                            "LatestPrerelease",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( == 1.2.1 && >= 2.3.3 && >= 3.2.3 )": {-                                        "dlCSize": 3,-                                        "dlHash": "ale",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease",-                                            "Experimental",-                                            "LatestPrerelease",-                                            "\u0017i\u0012\u0004sm",-                                            "Recommended",-                                            "old"-                                        ],-                                        "dlUri": "https:xtbe"-                                    }-                                },-                                "Linux_Alpine": {-                                    "unknown_versioning": {-                                        "dlCSize": -2,-                                        "dlHash": "y",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "􂜿+\u00184?"-                                        },-                                        "dlTag": [],-                                        "dlUri": "http:ivhil"-                                    }-                                },-                                "Linux_Ubuntu": {-                                    "( < 1.1.1 && > 3.5.2 && >= 4.4.2 && > 2.4.5 && > 1.1.4 )": {-                                        "dlCSize": 7,-                                        "dlHash": "euxrl",-                                        "dlOutput": "J",-                                        "dlSubdir": {-                                            "RegexDir": "e++'\u0008"-                                        },-                                        "dlTag": [-                                            "Nightly"-                                        ],-                                        "dlUri": "https:lypoc"-                                    },-                                    "( <= 4.1.2 && == 5.5.2 && < 1.5.4 && <= 3.4.1 && >= 4.1.2 && == 5.1.2 && <= 4.4.4 )": {-                                        "dlCSize": 7,-                                        "dlHash": "vyqcxr",-                                        "dlOutput": "~D",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "https:dv"-                                    },-                                    "( == 2.4.3 && >= 2.1.4 && <= 5.5.3 && > 3.1.5 && > 3.5.5 && > 1.5.4 )": {-                                        "dlCSize": 6,-                                        "dlHash": "o",-                                        "dlOutput": "\u0001|𤙑",-                                        "dlSubdir": "\u0003%􀯥Q",-                                        "dlTag": [-                                            "Latest",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:imb"-                                    },-                                    "( == 3.3.4 && < 3.4.3 && == 5.5.1 && <= 5.1.6 )": {-                                        "dlCSize": -2,-                                        "dlHash": "city",-                                        "dlOutput": "\\",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "Recommended"-                                        ],-                                        "dlUri": "https:bsytvq"-                                    },-                                    "( == 5.1.3 )": {-                                        "dlCSize": -3,-                                        "dlHash": "h",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "\u001d21",-                                            "LatestNightly",-                                            "Prerelease",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( >= 2.3.3 && <= 5.5.5 && > 5.2.1 ) || ( > 4.3.3 && == 4.2.3 && == 3.1.4 ) || ( > 1.2.2 && == 1.1.3 && == 3.1.2 ) || ( < 2.2.2 && < 1.2.1 && < 2.2.1 && < 1.1.2 )": {-                                        "dlCSize": -7,-                                        "dlHash": "",-                                        "dlOutput": "]L[􍂄",-                                        "dlSubdir": "<󽡦EM",-                                        "dlTag": [-                                            "Prerelease",-                                            "Nightly",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:ku"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "e",-                                        "dlOutput": "󲻑b",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "ꥵt"-                                        ],-                                        "dlUri": "https:"-                                    }-                                },-                                "Windows": {-                                    "( > 3.2.5 && > 4.2.3 && < 1.3.2 ) || ( > 1.4.1 && <= 5.3.4 )": {-                                        "dlCSize": -4,-                                        "dlHash": "pggkj",-                                        "dlOutput": "i𤨶F\u001a",-                                        "dlSubdir": "hi􀫟𲍏𮃥l",-                                        "dlTag": [-                                            "LatestNightly",-                                            "Experimental",-                                            "Experimental",-                                            "LatestPrerelease",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:fmnuwvr"-                                    }-                                }-                            }-                        },-                        "viChangeLog": "https:cx",-                        "viPostInstall": "cswgna",-                        "viPostRemove": "g",-                        "viPreCompile": "mxcsqv",-                        "viPreInstall": "bzguld",-                        "viReleaseDay": null,-                        "viSourceDL": null,-                        "viTags": [-                            "Latest"-                        ],-                        "viTestDL": {-                            "dlCSize": 2,-                            "dlHash": "soj",-                            "dlOutput": "\u000bx.i[",-                            "dlSubdir": null,-                            "dlTag": null,-                            "dlUri": "http:lqepg"-                        }-                    },-                    "5.8.7": {-                        "viArch": {-                            "A_ARM": {-                                "Darwin": {-                                    "( == 3.3.4 ) || ( >= 1.4.4 && < 4.1.2 && > 2.4.3 && == 2.4.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "jamb",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "􇤓𬃆S\r戝@"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    },-                                    "( == 5.2.4 && > 4.2.1 && == 3.2.1 && < 2.1.5 && > 2.2.4 && > 4.4.4 ) || ( == 1.4.1 && < 3.2.3 ) || ( > 2.3.3 && == 4.3.3 && >= 2.1.3 && == 2.2.2 ) || ( == 2.2.3 && < 2.1.2 && >= 1.1.1 && < 1.2.1 )": {-                                        "dlCSize": 7,-                                        "dlHash": "xhwmyw",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ",icW"-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "LatestPrerelease",-                                            "old",-                                            "Latest"-                                        ],-                                        "dlUri": "http:bpijwo"-                                    },-                                    "( > 3.5.4 ) || ( == 1.3.4 && > 3.2.4 )": {-                                        "dlCSize": -2,-                                        "dlHash": "tncs",-                                        "dlOutput": "V",-                                        "dlSubdir": {-                                            "RegexDir": "󺫼󶞬u"-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:bbsyej"-                                    },-                                    "( > 4.1.4 && <= 4.2.4 && <= 2.5.3 && < 5.5.2 && >= 1.2.5 && <= 3.3.5 ) || ( > 3.1.2 && <= 1.2.2 && <= 1.3.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "i",-                                        "dlOutput": "N1s7𫦳y",-                                        "dlSubdir": {-                                            "RegexDir": "(<趂u\u0015:"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:rrqqv"-                                    },-                                    "( >= 1.2.1 && >= 2.2.5 && == 2.5.4 ) || ( <= 4.3.4 && < 4.3.4 ) || ( == 1.3.2 && < 1.3.2 && < 2.2.2 && == 1.3.4 ) || ( >= 1.1.1 && >= 2.2.2 && == 1.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "kvoi",-                                        "dlOutput": "Qx\u0015\u001emW",-                                        "dlSubdir": {-                                            "RegexDir": "]`\u001d;pv"-                                        },-                                        "dlTag": [-                                            "Recommended",-                                            "LatestPrerelease",-                                            "LatestNightly",-                                            "Nightly",-                                            "\"!ⲕ",-                                            "Prerelease",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:szjihfe"-                                    },-                                    "( >= 2.4.5 ) || ( <= 1.1.6 && > 4.2.3 && < 1.2.4 && > 2.4.4 && == 3.3.2 && > 4.3.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "pwvvnm",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "NM\u001e,"-                                        },-                                        "dlTag": [-                                            "base-3.4.4"-                                        ],-                                        "dlUri": "https:yl"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "rrmn",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "t>>𦟯R4"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "LatestPrerelease",-                                            "Prerelease",-                                            "base-2.3.1",-                                            "Prerelease",-                                            "old"-                                        ],-                                        "dlUri": "https:w"-                                    }-                                },-                                "FreeBSD": {-                                    "( <= 5.4.5 && >= 5.5.5 && <= 5.5.5 && <= 5.3.1 && == 5.3.2 && > 1.3.3 ) || ( == 1.2.3 && >= 4.1.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "\u0003\u001aeNu􍅵"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:mqyrvs"-                                    },-                                    "( == 4.2.2 && == 3.1.4 ) || ( >= 3.1.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "hz",-                                        "dlOutput": "􆃅K^q𦺁",-                                        "dlSubdir": {-                                            "RegexDir": "朕"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:opas"-                                    },-                                    "( == 5.5.1 && == 3.1.3 )": {-                                        "dlCSize": 0,-                                        "dlHash": "qaxz",-                                        "dlOutput": "\u0010\u000e\u001c\u0005>",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "base-2.4.2",-                                            "Latest",-                                            "VY2𪢠)𘥖",-                                            "base-5.3.4",-                                            "base-5.3.4"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "( > 5.3.1 ) || ( <= 4.1.3 && <= 1.2.2 && >= 2.1.3 && == 3.2.2 )": {-                                        "dlCSize": -6,-                                        "dlHash": "xkghz",-                                        "dlOutput": ",𗘴\u0002𐡋\rw",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:onqrtyw"-                                    },-                                    "( >= 2.1.3 && == 4.1.3 && < 1.1.5 && == 1.5.4 && == 4.5.2 && > 1.3.3 && > 3.3.1 )": {-                                        "dlCSize": 1,-                                        "dlHash": "iggtp",-                                        "dlOutput": "`\u0008+E䢌7",-                                        "dlSubdir": {-                                            "RegexDir": "\u000e𧺚>􏇿"-                                        },-                                        "dlTag": [-                                            "I,\u000b텗",-                                            "Experimental",-                                            "Prerelease",-                                            "base-5.4.4",-                                            "𮄾𣢰\u000b6",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:tvukht"-                                    }-                                },-                                "Linux_Debian": {-                                    "( <= 5.2.5 && >= 1.2.5 && < 2.4.2 && <= 2.2.1 && <= 4.1.1 ) || ( >= 4.2.3 && > 3.1.2 && <= 4.1.3 && < 4.2.2 && == 4.1.1 && > 1.4.1 ) || ( == 1.1.3 && > 3.2.1 && <= 1.3.3 && == 3.3.3 && <= 3.1.2 )": {-                                        "dlCSize": 5,-                                        "dlHash": "",-                                        "dlOutput": "􍣛e]\u0001u",-                                        "dlSubdir": {-                                            "RegexDir": "`\u0016"-                                        },-                                        "dlTag": [-                                            "old",-                                            "old"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "cpunfek",-                                        "dlOutput": "{\"",-                                        "dlSubdir": "\u00081\u0011",-                                        "dlTag": [-                                            "Recommended",-                                            "Nightly",-                                            "Latest",-                                            "Experimental",-                                            "Latest"-                                        ],-                                        "dlUri": "https:l"-                                    }-                                },-                                "Windows": {-                                    "( <= 2.4.1 && < 5.1.2 && >= 4.3.1 && <= 1.4.1 && == 5.5.1 )": {-                                        "dlCSize": 1,-                                        "dlHash": "eq",-                                        "dlOutput": "Y\u0010\u000e\u000c\u0012",-                                        "dlSubdir": "%𬁁<",-                                        "dlTag": null,-                                        "dlUri": "https:tg"-                                    },-                                    "( <= 3.5.5 && <= 3.1.5 && < 4.3.1 && <= 4.4.1 && >= 1.1.2 )": {-                                        "dlCSize": -5,-                                        "dlHash": "uodlhxa",-                                        "dlOutput": "",-                                        "dlSubdir": "",-                                        "dlTag": null,-                                        "dlUri": "https:"-                                    },-                                    "( == 3.5.4 && >= 3.2.3 && > 3.4.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "erdegjk",-                                        "dlOutput": null,-                                        "dlSubdir": "讃",-                                        "dlTag": [],-                                        "dlUri": "https:vz"-                                    },-                                    "( >= 2.1.4 ) || ( < 3.3.1 && == 4.1.2 && >= 1.4.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "gumj",-                                        "dlOutput": "\u001a󸶘􌳯",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:wykdw"-                                    },-                                    "( >= 2.4.2 && >= 2.4.4 && <= 4.4.2 && >= 3.3.2 && > 5.4.3 && == 5.3.4 )": {-                                        "dlCSize": -7,-                                        "dlHash": "vkmdkgw",-                                        "dlOutput": "",-                                        "dlSubdir": "",-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    }-                                }-                            }-                        },-                        "viChangeLog": null,-                        "viPostInstall": "nrmxph",-                        "viPostRemove": "vabzro",-                        "viPreCompile": null,-                        "viPreInstall": "cfyw",-                        "viReleaseDay": null,-                        "viSourceDL": {-                            "dlCSize": 3,-                            "dlHash": "dnzbvt",-                            "dlOutput": "",-                            "dlSubdir": "4\u0012𜾾R",-                            "dlTag": [-                                "Latest",-                                "base-4.1.1"-                            ],-                            "dlUri": "http:h"-                        },-                        "viTags": [-                            "Experimental",-                            "Prerelease",-                            "old",-                            "Nightly"-                        ],-                        "viTestDL": {-                            "dlCSize": null,-                            "dlHash": "",-                            "dlOutput": null,-                            "dlSubdir": {-                                "RegexDir": "I"-                            },-                            "dlTag": [-                                "Nightly"-                            ],-                            "dlUri": "https:tpnlb"-                        }-                    },-                    "8.4.2": {-                        "viArch": {-                            "A_PowerPC": {-                                "Darwin": {},-                                "Linux_Debian": {-                                    "( < 3.2.3 && < 2.3.5 && < 3.1.1 && >= 2.2.4 && > 4.2.2 && == 5.4.3 && < 1.1.2 )": {-                                        "dlCSize": -2,-                                        "dlHash": "oake",-                                        "dlOutput": "",-                                        "dlSubdir": " ၰY",-                                        "dlTag": [-                                            "base-3.2.4",-                                            "Prerelease",-                                            "LatestNightly",-                                            "Latest",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:uudjbeh"-                                    },-                                    "( < 3.2.4 && > 5.2.2 && > 3.1.4 && == 5.2.5 && == 5.5.2 && <= 2.4.4 && >= 3.3.5 ) || ( == 3.1.1 ) || ( < 2.2.3 && == 3.1.4 && <= 1.1.1 )": {-                                        "dlCSize": 3,-                                        "dlHash": "aah",-                                        "dlOutput": "\t@P\u0007E",-                                        "dlSubdir": {-                                            "RegexDir": "6傭''"-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "Nightly",-                                            "Latest",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:c"-                                    },-                                    "( < 4.3.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "inf",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease",-                                            "Nightly",-                                            "Experimental",-                                            "LatestNightly",-                                            "old",-                                            "Latest"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( < 5.1.1 && <= 1.3.4 && >= 2.4.4 ) || ( >= 1.2.3 && < 4.3.4 && == 4.1.3 && > 4.4.2 ) || ( == 2.1.1 && < 3.1.2 && == 1.4.1 && < 1.3.2 && >= 2.3.3 ) || ( >= 2.1.2 && == 2.2.1 && == 2.2.1 ) || ( <= 1.1.1 && < 2.1.1 && >= 1.1.1 )": {-                                        "dlCSize": -3,-                                        "dlHash": "z",-                                        "dlOutput": "*z{Y",-                                        "dlSubdir": "\nUuD\u001f",-                                        "dlTag": null,-                                        "dlUri": "http:zan"-                                    },-                                    "( == 5.3.3 && <= 2.3.3 ) || ( < 4.3.4 && < 5.4.4 && >= 1.3.2 && == 1.2.1 && <= 1.4.2 )": {-                                        "dlCSize": 3,-                                        "dlHash": "fmofl",-                                        "dlOutput": "\u0012X*ꇛmk",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:xgw"-                                    },-                                    "( > 2.3.4 && == 2.4.1 ) || ( > 5.3.5 && >= 2.2.2 && == 3.3.1 && > 2.2.2 ) || ( == 1.3.3 && > 3.2.2 ) || ( <= 2.1.1 )": {-                                        "dlCSize": -3,-                                        "dlHash": "td",-                                        "dlOutput": "\u0004\u0014\u0000􊱻d;䞏",-                                        "dlSubdir": {-                                            "RegexDir": "𰼚`rp"-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:qsy"-                                    },-                                    "( >= 1.1.1 && < 2.1.2 && < 5.4.4 && > 5.2.5 && < 3.4.2 && >= 4.1.1 ) || ( <= 3.4.4 ) || ( >= 1.2.2 && == 1.3.2 && >= 1.3.3 && < 2.2.1 && <= 2.3.1 )": {-                                        "dlCSize": 7,-                                        "dlHash": "yq",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "텦󷼗d"-                                        },-                                        "dlTag": [-                                            "old",-                                            "old",-                                            "Experimental",-                                            "Prerelease",-                                            "Experimental",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( >= 4.2.1 && >= 4.4.2 )": {-                                        "dlCSize": -1,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": "!5]􅁘:􇿈",-                                        "dlTag": [],-                                        "dlUri": "https:uoltbef"-                                    }-                                }-                            },-                            "A_Sparc": {-                                "FreeBSD": {-                                    "( < 2.1.4 && > 5.3.3 && == 5.2.3 ) || ( >= 4.2.2 && > 1.5.3 && < 1.2.3 && < 2.4.2 ) || ( <= 3.1.3 && >= 3.2.2 && <= 2.3.1 )": {-                                        "dlCSize": -3,-                                        "dlHash": "fkhdm",-                                        "dlOutput": ".\u0019\u000eF%􆚂~",-                                        "dlSubdir": "Y􊩠'7",-                                        "dlTag": [-                                            ""-                                        ],-                                        "dlUri": "http:p"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "parxfp",-                                        "dlOutput": "",-                                        "dlSubdir": "D",-                                        "dlTag": null,-                                        "dlUri": "http:jnmhm"-                                    }-                                }-                            }-                        },-                        "viChangeLog": null,-                        "viPostInstall": "hk",-                        "viPostRemove": "qwprb",-                        "viPreCompile": "jxnoav",-                        "viPreInstall": "u",-                        "viReleaseDay": "19934051486464766-02-01",-                        "viSourceDL": {-                            "dlCSize": -4,-                            "dlHash": "v",-                            "dlOutput": null,-                            "dlSubdir": "",-                            "dlTag": null,-                            "dlUri": "https:gtcg"-                        },-                        "viTags": [-                            "LatestNightly",-                            "old",-                            "LatestPrerelease",-                            "Nightly",-                            "Recommended",-                            "LatestNightly",-                            "old"-                        ],-                        "viTestDL": {-                            "dlCSize": 3,-                            "dlHash": "vn",-                            "dlOutput": "",-                            "dlSubdir": "",-                            "dlTag": [-                                "Nightly",-                                "f`P'",-                                "Prerelease",-                                "LatestNightly",-                                "LatestNightly"-                            ],-                            "dlUri": "https:vhl"-                        }-                    },-                    "8.7.6": {-                        "viArch": {-                            "A_32": {-                                "FreeBSD": {-                                    "( < 1.1.4 && > 3.5.4 && > 5.1.4 && <= 1.3.2 && <= 5.5.4 ) || ( > 1.4.3 && <= 1.3.2 && < 2.4.1 )": {-                                        "dlCSize": 2,-                                        "dlHash": "c",-                                        "dlOutput": "M𒄧",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:prex"-                                    },-                                    "( <= 5.4.6 && > 2.4.4 && <= 2.2.4 && >= 5.5.1 && == 2.3.5 ) || ( > 5.3.4 && <= 1.1.3 && <= 2.2.2 )": {-                                        "dlCSize": -6,-                                        "dlHash": "hvgpo",-                                        "dlOutput": "/\u0006",-                                        "dlSubdir": {-                                            "RegexDir": "2닪\u000f"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "LatestNightly",-                                            "old",-                                            "Recommended",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:bpegya"-                                    },-                                    "( == 2.1.3 && == 2.1.3 && < 5.5.2 && == 6.5.2 && > 4.4.2 ) || ( == 4.3.1 && == 1.2.2 && > 1.2.6 && == 1.3.3 && == 3.1.3 && >= 3.4.4 )": {-                                        "dlCSize": -3,-                                        "dlHash": "yhyup",-                                        "dlOutput": "\u001dm3?&􁭏\u0018",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:i"-                                    },-                                    "( == 3.4.5 && >= 2.3.5 && > 4.3.2 && >= 2.5.3 && >= 5.4.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "hmvpk",-                                        "dlOutput": "\u0000jb",-                                        "dlSubdir": {-                                            "RegexDir": "󾕩\u0003𖪈"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "LatestPrerelease",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:rqrkcd"-                                    },-                                    "( > 2.4.4 )": {-                                        "dlCSize": 5,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Latest"-                                        ],-                                        "dlUri": "https:o"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -5,-                                        "dlHash": "",-                                        "dlOutput": "h􎻐\u001d",-                                        "dlSubdir": "K銴",-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    }-                                },-                                "Linux_CentOS": {-                                    "( < 2.2.3 && < 4.1.4 && < 1.4.5 && == 4.5.4 && > 2.3.3 && < 3.2.3 && <= 5.3.3 ) || ( > 2.4.4 ) || ( == 1.4.3 && > 1.1.1 ) || ( >= 1.2.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "qtvqnpr",-                                        "dlOutput": null,-                                        "dlSubdir": "\u000f\\󻥤<C熿",-                                        "dlTag": [-                                            "base-1.2.2"-                                        ],-                                        "dlUri": "https:mpy"-                                    },-                                    "( < 4.4.4 && > 3.2.1 && > 3.1.2 ) || ( <= 1.4.3 && > 1.3.4 && == 4.2.1 && <= 3.3.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "ct",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:fxlo"-                                    },-                                    "( <= 2.4.1 ) || ( < 4.3.2 ) || ( < 1.2.2 && >= 2.2.1 ) || ( >= 2.2.1 && < 2.2.1 && < 2.1.2 && >= 2.1.1 ) || ( >= 1.2.1 && <= 1.1.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "tkdaczs",-                                        "dlOutput": "E",-                                        "dlSubdir": ")T\u000eh",-                                        "dlTag": [-                                            "Prerelease",-                                            "Experimental",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:"-                                    }-                                },-                                "Linux_RedHat": {-                                    "unknown_versioning": {-                                        "dlCSize": 0,-                                        "dlHash": "dwx",-                                        "dlOutput": "\u00102\"9s\u00062",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "Experimental",-                                            "LatestNightly",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:rypeki"-                                    }-                                },-                                "Windows": {-                                    "( <= 3.2.5 && < 2.3.2 && > 5.6.3 && == 2.4.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "thdaqe",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "Latest"-                                        ],-                                        "dlUri": "http:ayuhoj"-                                    },-                                    "( == 2.1.4 && == 1.2.2 && <= 3.3.1 && > 4.4.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "sf",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Recommended",-                                            ".",-                                            "Nightly",-                                            "old",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:irwc"-                                    },-                                    "( > 4.3.1 && <= 3.4.3 && <= 3.5.1 && < 2.5.4 && >= 2.4.2 ) || ( < 2.2.2 && >= 2.2.3 && == 2.2.4 && > 2.4.2 )": {-                                        "dlCSize": -2,-                                        "dlHash": "tqmns",-                                        "dlOutput": "\u0001",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "Recommended"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "( >= 2.2.5 && < 1.4.5 && >= 3.2.3 )": {-                                        "dlCSize": -4,-                                        "dlHash": "f",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "R􀮹𤃒\\!"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:va"-                                    }-                                }-                            },-                            "A_64": {-                                "FreeBSD": {-                                    "( < 3.4.4 && <= 4.4.2 )": {-                                        "dlCSize": -3,-                                        "dlHash": "edeeu",-                                        "dlOutput": "􊢝\\/bWI",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "https:vmgy"-                                    },-                                    "( >= 1.4.2 ) || ( <= 4.2.2 && == 4.3.2 ) || ( == 2.2.3 && >= 1.4.1 && < 1.2.2 && <= 3.1.2 && == 1.2.4 ) || ( <= 2.2.1 ) || ( >= 1.1.1 && >= 1.1.1 && < 1.1.1 )": {-                                        "dlCSize": -2,-                                        "dlHash": "t",-                                        "dlOutput": "=\u0017",-                                        "dlSubdir": {-                                            "RegexDir": "𰙌{_𘲅\\᳙"-                                        },-                                        "dlTag": [-                                            "",-                                            "Latest",-                                            "Latest",-                                            "LatestNightly",-                                            "Latest"-                                        ],-                                        "dlUri": "http:woiqer"-                                    },-                                    "( >= 2.4.1 && > 5.4.6 && == 1.2.3 && <= 4.4.2 && <= 2.1.1 && > 1.5.5 ) || ( >= 3.3.4 && == 2.4.2 && > 1.1.3 && < 4.1.3 && >= 3.3.1 && <= 2.1.4 ) || ( > 3.2.1 && >= 1.2.2 && >= 1.2.1 && <= 2.1.2 ) || ( <= 2.1.3 && < 2.1.2 && <= 1.1.1 ) || ( < 2.1.1 && <= 1.1.1 && <= 1.1.1 )": {-                                        "dlCSize": -6,-                                        "dlHash": "vqsoy",-                                        "dlOutput": "\u0002/Xg",-                                        "dlSubdir": "􀒫\r\u0014",-                                        "dlTag": [-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( >= 3.5.3 && == 1.2.1 && <= 3.5.1 && <= 4.4.4 && <= 1.5.2 && > 3.2.5 ) || ( >= 3.4.1 && >= 3.2.3 && >= 3.3.1 && < 4.3.3 ) || ( <= 1.2.3 && >= 3.2.2 && >= 2.2.4 )": {-                                        "dlCSize": 1,-                                        "dlHash": "n",-                                        "dlOutput": "\u000e",-                                        "dlSubdir": {-                                            "RegexDir": "􏢞Jni"-                                        },-                                        "dlTag": [],-                                        "dlUri": "http:bwwfhoy"-                                    }-                                },-                                "Linux_AmazonLinux": {-                                    "( < 2.3.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "dchgqk",-                                        "dlOutput": "",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "Experimental",-                                            "Experimental",-                                            "Nightly",-                                            "Recommended",-                                            "base-5.4.5",-                                            "Latest",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:gvw"-                                    },-                                    "( == 1.2.2 && > 1.5.4 && >= 1.3.4 && > 2.3.1 && == 3.2.1 && == 3.5.5 ) || ( < 2.2.2 ) || ( <= 3.2.2 && > 3.3.1 && >= 2.2.1 ) || ( > 2.1.3 && >= 1.2.1 ) || ( < 1.1.1 && >= 1.1.1 )": {-                                        "dlCSize": -3,-                                        "dlHash": "rmv",-                                        "dlOutput": "D\ni\u0017",-                                        "dlSubdir": {-                                            "RegexDir": "tfs+"-                                        },-                                        "dlTag": [],-                                        "dlUri": "http:vg"-                                    },-                                    "( == 3.1.3 && == 5.2.5 && >= 4.1.4 ) || ( >= 4.4.1 && >= 1.2.4 && >= 1.3.1 && >= 1.1.1 && <= 5.3.3 && >= 1.3.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "ylmn",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "base-3.6.6",-                                            "LatestNightly",-                                            "Nightly",-                                            "base-1.5.1"-                                        ],-                                        "dlUri": "http:zivq"-                                    },-                                    "( > 5.1.3 && == 1.4.5 && == 2.3.5 && < 2.1.5 && == 1.2.2 && >= 5.5.1 && == 4.4.3 ) || ( == 3.3.3 && <= 1.1.1 && < 4.1.4 && >= 2.1.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "gcfd",-                                        "dlOutput": "s󾁩-b\u0002菹",-                                        "dlSubdir": "𗈝󾂃\u0015\u000e󴬻\u0008",-                                        "dlTag": [-                                            "LatestNightly",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:qac"-                                    },-                                    "( >= 5.1.5 )": {-                                        "dlCSize": 0,-                                        "dlHash": "bd",-                                        "dlOutput": "䫫􊃢t}􏋋q󷊰",-                                        "dlSubdir": {-                                            "RegexDir": "V藣􊵕\u000bu𗖖"-                                        },-                                        "dlTag": [-                                            "old",-                                            "base-1.4.4",-                                            "Nightly",-                                            "old"-                                        ],-                                        "dlUri": "https:hslqrk"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "tjgjhc",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "&}_"-                                        },-                                        "dlTag": [-                                            "old",-                                            "Recommended",-                                            "Latest",-                                            "LatestPrerelease",-                                            "Recommended",-                                            "Prerelease",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:t"-                                    }-                                },-                                "Linux_CentOS": {-                                    "( < 2.6.2 && > 2.1.2 && <= 1.3.5 && >= 4.4.5 && >= 1.4.2 && > 3.4.5 )": {-                                        "dlCSize": -6,-                                        "dlHash": "",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "𘍞𑨸"-                                        },-                                        "dlTag": [-                                            "old",-                                            "base-5.6.6",-                                            "Latest",-                                            "Latest",-                                            "Latest",-                                            "Latest"-                                        ],-                                        "dlUri": "http:iktwsyx"-                                    },-                                    "( < 4.3.5 && == 1.5.4 && >= 5.3.2 && == 3.1.1 && >= 2.1.1 )": {-                                        "dlCSize": -6,-                                        "dlHash": "saqxln",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "\u0013DH\u0016\u000f"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:fhr"-                                    },-                                    "( == 3.4.5 && > 3.3.1 ) || ( > 3.2.2 && > 1.4.4 && == 1.4.4 && <= 2.2.3 && == 2.3.3 )": {-                                        "dlCSize": 7,-                                        "dlHash": "ruh",-                                        "dlOutput": "𨔡I\u0018>󲍺\\Z",-                                        "dlSubdir": {-                                            "RegexDir": ">𮓴\u001b\u0005"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:tyu"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 7,-                                        "dlHash": "",-                                        "dlOutput": "g󼡧C",-                                        "dlSubdir": {-                                            "RegexDir": "d12vᦃ\u001a"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:"-                                    }-                                },-                                "Linux_Debian": {-                                    "( <= 1.3.2 && < 1.3.5 && == 3.1.4 && <= 2.5.2 && <= 6.3.2 && >= 2.3.5 )": {-                                        "dlCSize": 1,-                                        "dlHash": "kqsmsw",-                                        "dlOutput": "-U\u000e\u0001TH",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease",-                                            "",-                                            "old",-                                            "Recommended",-                                            "E.:C",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:l"-                                    },-                                    "( <= 5.5.3 && > 4.1.5 && < 1.3.3 && >= 5.3.4 && > 2.2.4 && < 1.4.4 && >= 4.2.5 ) || ( >= 4.1.2 && > 4.2.3 && <= 3.1.1 ) || ( <= 3.1.3 && < 2.2.2 && >= 2.1.4 && > 2.3.2 && <= 1.1.1 )": {-                                        "dlCSize": 1,-                                        "dlHash": "rbxnq",-                                        "dlOutput": ")%🃪2",-                                        "dlSubdir": {-                                            "RegexDir": "U-\u0019"-                                        },-                                        "dlTag": [-                                            "Latest",-                                            "base-3.2.4",-                                            "base-2.2.2"-                                        ],-                                        "dlUri": "https:cntexx"-                                    },-                                    "( == 2.1.2 && > 3.1.1 && == 1.5.2 && > 4.4.5 && > 6.1.2 && < 3.3.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "hr",-                                        "dlOutput": "i\u0015𥤑",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "Latest",-                                            "LatestPrerelease",-                                            "old"-                                        ],-                                        "dlUri": "https:geajrro"-                                    },-                                    "( >= 1.3.3 && >= 3.3.3 && > 3.1.2 )": {-                                        "dlCSize": -7,-                                        "dlHash": "epd",-                                        "dlOutput": "#􍹿𥼼",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease",-                                            "Latest"-                                        ],-                                        "dlUri": "https:qtjv"-                                    },-                                    "( >= 4.1.1 ) || ( == 2.2.1 && >= 4.4.1 )": {-                                        "dlCSize": -3,-                                        "dlHash": "ycgcn",-                                        "dlOutput": "Q\u001f𫿯\u000c",-                                        "dlSubdir": {-                                            "RegexDir": "\tCR"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "\u0019,q1x"-                                        ],-                                        "dlUri": "http:lzqtp"-                                    }-                                },-                                "Linux_Ubuntu": {-                                    "( < 1.3.5 && < 1.6.4 && > 2.4.1 && >= 2.4.5 ) || ( >= 4.3.1 && >= 1.1.2 ) || ( <= 2.2.2 && <= 3.1.2 && < 1.2.1 ) || ( < 1.3.2 && < 1.2.1 && >= 1.2.4 ) || ( < 2.2.1 && == 1.1.1 ) || ( == 1.1.1 ) || ( > 2.1.1 ) || ( < 1.1.1 )": {-                                        "dlCSize": 7,-                                        "dlHash": "r",-                                        "dlOutput": "􌏷\n󴦲󼁆䨢z",-                                        "dlSubdir": "𨩠?7􁘍",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "\u001e待𩡊k",-                                            "D!"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -7,-                                        "dlHash": "rhslpof",-                                        "dlOutput": "𱅉;",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease",-                                            "X\u0018$V𝥚~"-                                        ],-                                        "dlUri": "http:bk"-                                    }-                                },-                                "Windows": {-                                    "( < 4.4.5 )": {-                                        "dlCSize": 7,-                                        "dlHash": "hc",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "5"-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "base-2.3.5",-                                            "Recommended",-                                            "LatestNightly",-                                            "old",-                                            "Latest",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:rqiwv"-                                    },-                                    "( <= 1.1.1 && > 2.2.2 && >= 4.1.1 && == 3.1.1 && > 1.2.3 && <= 2.2.5 && <= 5.4.1 )": {-                                        "dlCSize": 3,-                                        "dlHash": "l",-                                        "dlOutput": "UB$𤌎0\u0006",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "t𤺈"-                                        ],-                                        "dlUri": "http:gmhnh"-                                    },-                                    "( <= 1.4.3 && >= 1.5.4 && <= 2.4.1 && > 3.2.1 ) || ( >= 4.1.1 ) || ( > 2.2.2 && > 3.3.1 ) || ( <= 2.1.3 && >= 2.1.1 && <= 1.2.2 ) || ( < 1.1.2 && > 1.2.1 && < 1.2.1 )": {-                                        "dlCSize": 2,-                                        "dlHash": "rs",-                                        "dlOutput": "",-                                        "dlSubdir": "󲮆=",-                                        "dlTag": [],-                                        "dlUri": "http:lrfih"-                                    }-                                }-                            },-                            "A_ARM": {-                                "Darwin": {-                                    "( < 5.4.5 && >= 5.5.2 && < 1.5.3 && >= 1.4.5 ) || ( > 4.2.2 && == 2.3.4 )": {-                                        "dlCSize": 1,-                                        "dlHash": "fd",-                                        "dlOutput": "/}<u\u001a",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "old",-                                            "'\u0008l\u0015n",-                                            "old",-                                            "Experimental",-                                            "base-3.6.3"-                                        ],-                                        "dlUri": "https:yfjj"-                                    },-                                    "( <= 3.3.3 && < 2.3.5 && <= 3.2.2 )": {-                                        "dlCSize": 7,-                                        "dlHash": "hnht",-                                        "dlOutput": "\u0001@W芞\u001e1",-                                        "dlSubdir": "\u000bYu󻒆",-                                        "dlTag": [-                                            "\u0005\u0002",-                                            "LatestNightly",-                                            "C􂄕UU[",-                                            "M;+"-                                        ],-                                        "dlUri": "http:fzq"-                                    },-                                    "( <= 4.5.1 && > 5.3.4 && == 2.1.4 && > 3.3.1 && == 1.4.2 && == 4.2.4 && == 4.3.4 )": {-                                        "dlCSize": 3,-                                        "dlHash": "",-                                        "dlOutput": ")_x",-                                        "dlSubdir": "󷼜N\u0014\u001d",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "",-                                            "LatestNightly",-                                            "Recommended",-                                            "󰲪>0h",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( > 3.2.3 ) || ( >= 4.4.1 && > 3.1.4 && == 3.1.3 && == 4.4.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "vmt",-                                        "dlOutput": "\u0010%",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "https:uzrb"-                                    },-                                    "( >= 4.4.3 && > 4.4.3 && > 2.2.5 && == 2.4.3 && <= 4.3.3 ) || ( <= 4.2.5 && <= 2.4.1 && >= 2.5.3 ) || ( <= 2.1.3 && < 2.1.1 ) || ( <= 1.1.1 && == 2.1.3 )": {-                                        "dlCSize": -1,-                                        "dlHash": "coln",-                                        "dlOutput": "}\u0007􆁜z",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Recommended",-                                            "Latest",-                                            "Nightly",-                                            "q𬏕46"-                                        ],-                                        "dlUri": "https:k"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 2,-                                        "dlHash": "",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "\u0000\u001ec"-                                        },-                                        "dlTag": [-                                            "old"-                                        ],-                                        "dlUri": "https:nun"-                                    }-                                }-                            },-                            "A_ARM64": {-                                "Darwin": {-                                    "( == 2.5.5 && == 1.4.3 && > 4.4.2 && <= 5.3.3 )": {-                                        "dlCSize": 0,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "L:@\u0000􀠉"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:"-                                    },-                                    "( > 2.2.2 && > 1.2.5 && < 4.4.3 && < 4.3.2 && > 4.1.1 && > 4.3.5 ) || ( > 1.4.1 && < 2.1.3 && > 1.4.1 && > 4.1.1 ) || ( >= 1.3.3 && <= 3.2.1 && == 1.2.3 && < 2.2.1 && < 3.1.3 ) || ( == 3.1.3 && <= 2.2.1 ) || ( > 2.1.2 && < 1.1.2 && > 1.1.1 ) || ( <= 2.1.1 && < 1.1.2 ) || ( == 2.1.1 ) || ( < 1.1.1 ) || ( > 1.3.1 ) || ( < 1.1.1 )": {-                                        "dlCSize": -4,-                                        "dlHash": "elgeoic",-                                        "dlOutput": "$J",-                                        "dlSubdir": {-                                            "RegexDir": "󻏵\u0019t"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:ku"-                                    },-                                    "( >= 1.2.4 )": {-                                        "dlCSize": 6,-                                        "dlHash": "hgpjt",-                                        "dlOutput": ",⫅9",-                                        "dlSubdir": {-                                            "RegexDir": "󴤄𖥭􋘵n󰜖V"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:hzs"-                                    }-                                },-                                "Linux_RedHat": {-                                    "( == 4.3.6 && > 6.1.2 && < 4.4.1 && >= 3.1.1 )": {-                                        "dlCSize": -7,-                                        "dlHash": "",-                                        "dlOutput": "Y\n83?󽯅",-                                        "dlSubdir": "\u0006",-                                        "dlTag": [-                                            "Experimental",-                                            "Nightly",-                                            "Experimental",-                                            "Nightly",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:xz"-                                    },-                                    "( == 5.5.1 && <= 5.4.5 && > 4.2.4 && == 5.4.4 )": {-                                        "dlCSize": 4,-                                        "dlHash": "",-                                        "dlOutput": "󸽞",-                                        "dlSubdir": {-                                            "RegexDir": "Z𩗲\u0014K"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:ewc"-                                    },-                                    "( > 3.2.1 ) || ( < 1.1.2 && >= 2.3.3 )": {-                                        "dlCSize": -7,-                                        "dlHash": "fszk",-                                        "dlOutput": null,-                                        "dlSubdir": "Q󾆏f\u00026Y",-                                        "dlTag": [-                                            "Recommended",-                                            "Latest",-                                            "Latest",-                                            "Latest",-                                            "Nightly",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:qse"-                                    },-                                    "( >= 3.3.3 && >= 3.3.4 && == 1.4.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "nc",-                                        "dlOutput": "]]4𦁪\u0001<!",-                                        "dlSubdir": {-                                            "RegexDir": "𫟝𡲮𢒵`"-                                        },-                                        "dlTag": [-                                            "old",-                                            "LatestPrerelease",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:sokqq"-                                    },-                                    "( >= 3.4.1 && == 2.5.2 && < 4.3.1 && >= 4.2.4 ) || ( <= 5.5.3 && >= 2.3.1 && >= 1.4.4 && <= 4.2.1 && < 2.4.1 && < 3.1.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "j",-                                        "dlOutput": null,-                                        "dlSubdir": "KP",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:qog"-                                    },-                                    "( >= 4.5.2 && >= 2.2.4 && <= 2.5.5 && >= 3.2.5 ) || ( < 3.2.1 ) || ( > 2.1.3 && >= 2.1.2 && < 2.2.3 && <= 2.1.2 && > 2.1.2 )": {-                                        "dlCSize": 1,-                                        "dlHash": "zrdpwog",-                                        "dlOutput": "\u000cMe󽝋",-                                        "dlSubdir": "t\nr3Tc",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "old",-                                            "LatestNightly",-                                            "Z",-                                            "old"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -3,-                                        "dlHash": "b",-                                        "dlOutput": "",-                                        "dlSubdir": "󼽱ANY",-                                        "dlTag": null,-                                        "dlUri": "http:xuvjfc"-                                    }-                                },-                                "Linux_Void": {-                                    "unknown_versioning": {-                                        "dlCSize": -2,-                                        "dlHash": "t",-                                        "dlOutput": "7󿮧\u001f",-                                        "dlSubdir": "\u001a",-                                        "dlTag": [],-                                        "dlUri": "http:hrm"-                                    }-                                },-                                "Windows": {-                                    "( <= 3.2.1 && == 1.2.2 && < 5.2.4 && < 3.4.1 )": {-                                        "dlCSize": 4,-                                        "dlHash": "jybp",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestNightly",-                                            "old",-                                            "old",-                                            "Latest",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:takejc"-                                    },-                                    "( >= 3.3.2 && > 2.5.1 && <= 2.2.1 && > 4.4.4 && > 4.5.5 && > 1.5.5 && <= 3.3.3 ) || ( >= 3.1.3 && <= 2.4.2 && > 3.1.2 && > 3.3.2 && < 3.3.1 )": {-                                        "dlCSize": -1,-                                        "dlHash": "olbjtc",-                                        "dlOutput": "09B𰪶",-                                        "dlSubdir": "&譢\u0000+",-                                        "dlTag": [-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:exmlnxg"-                                    },-                                    "( >= 4.4.1 )": {-                                        "dlCSize": -5,-                                        "dlHash": "zolnvlr",-                                        "dlOutput": "\u0002󴝒\u0007􁮶",-                                        "dlSubdir": {-                                            "RegexDir": "Z𱺂"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "LatestNightly",-                                            "Latest",-                                            "Latest",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:ropwq"-                                    },-                                    "( >= 5.4.4 && > 1.2.5 && < 1.4.6 && < 5.1.4 && == 5.1.1 ) || ( > 3.3.1 && <= 3.1.4 && < 4.1.2 ) || ( < 3.2.1 && >= 1.3.1 && < 3.3.1 && <= 1.1.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "ptqdq",-                                        "dlOutput": "\u001cSV",-                                        "dlSubdir": "Ac",-                                        "dlTag": [-                                            "Nightly",-                                            "\u0003𐿇`1/",-                                            "Recommended",-                                            "LatestNightly",-                                            "Nightly",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:axygq"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 5,-                                        "dlHash": "dxmk",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": ".\u000c"-                                        },-                                        "dlTag": [-                                            "old",-                                            "old",-                                            "old",-                                            "",-                                            "\"",-                                            "Latest",-                                            "old"-                                        ],-                                        "dlUri": "https:yahdkck"-                                    }-                                }-                            },-                            "A_Sparc64": {-                                "Darwin": {-                                    "( <= 3.4.2 && < 1.3.1 && > 1.1.4 && <= 6.4.4 && < 2.3.2 && > 3.2.2 && == 3.3.7 )": {-                                        "dlCSize": -5,-                                        "dlHash": "wnbu",-                                        "dlOutput": null,-                                        "dlSubdir": "𗵡{2",-                                        "dlTag": [-                                            "Experimental"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( >= 1.5.1 )": {-                                        "dlCSize": 1,-                                        "dlHash": "gbnak",-                                        "dlOutput": "꞊",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Recommended",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:lvm"-                                    }-                                },-                                "FreeBSD": {-                                    "unknown_versioning": {-                                        "dlCSize": 5,-                                        "dlHash": "ao",-                                        "dlOutput": "",-                                        "dlSubdir": "\u0013",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Nightly",-                                            "Prerelease",-                                            ">󴽁"-                                        ],-                                        "dlUri": "https:tvrk"-                                    }-                                },-                                "Linux_Void": {-                                    "( <= 1.2.5 && < 3.4.4 ) || ( <= 4.1.2 && > 3.3.2 ) || ( <= 3.3.3 && < 3.1.2 && >= 4.1.1 && <= 2.3.4 && < 2.1.1 )": {-                                        "dlCSize": -1,-                                        "dlHash": "vixd",-                                        "dlOutput": "",-                                        "dlSubdir": "R\u0004",-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    },-                                    "( <= 3.5.4 )": {-                                        "dlCSize": -5,-                                        "dlHash": "umsg",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "\u001b"-                                        },-                                        "dlTag": [-                                            "base-5.5.5",-                                            "LatestNightly",-                                            "LatestNightly",-                                            "\u0010}",-                                            " K5_",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:fw"-                                    },-                                    "( <= 4.5.1 && < 5.2.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "gftay",-                                        "dlOutput": "eHg",-                                        "dlSubdir": "`*\u001a\"",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Latest",-                                            "LatestNightly",-                                            "LatestPrerelease",-                                            "LatestNightly",-                                            "base-4.6.4",-                                            "@j8뎹"-                                        ],-                                        "dlUri": "http:grys"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -4,-                                        "dlHash": "iqbx",-                                        "dlOutput": null,-                                        "dlSubdir": "t",-                                        "dlTag": [-                                            "Experimental",-                                            "LatestPrerelease",-                                            "Prerelease",-                                            "Recommended",-                                            "Latest",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:vourzma"-                                    }-                                },-                                "Windows": {-                                    "( < 3.2.5 && >= 5.1.1 && < 2.1.3 && > 5.2.1 ) || ( <= 1.3.1 && <= 1.4.1 && == 3.2.4 && >= 2.4.2 && < 3.1.1 && == 4.1.4 ) || ( <= 3.3.3 && >= 3.1.3 && >= 1.1.3 && > 2.2.1 )": {-                                        "dlCSize": 1,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": "^3",-                                        "dlTag": [],-                                        "dlUri": "http:qme"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "shfoo",-                                        "dlOutput": "諆𥛢/a ",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "http:z"-                                    }-                                }-                            }-                        },-                        "viChangeLog": null,-                        "viPostInstall": null,-                        "viPostRemove": "eyxan",-                        "viPreCompile": "whwdbl",-                        "viPreInstall": "r",-                        "viReleaseDay": "-19419099547954845-03-07",-                        "viSourceDL": null,-                        "viTags": [-                            "Nightly",-                            "Recommended"-                        ],-                        "viTestDL": {-                            "dlCSize": 1,-                            "dlHash": "",-                            "dlOutput": "\u0016𢇉N",-                            "dlSubdir": {-                                "RegexDir": ""-                            },-                            "dlTag": [],-                            "dlUri": "https:aio"-                        }-                    },-                    "8.8.5": {-                        "viArch": {-                            "A_32": {-                                "Darwin": {-                                    "( < 1.5.1 && <= 4.5.3 )": {-                                        "dlCSize": -2,-                                        "dlHash": "zgxddf",-                                        "dlOutput": "6%m",-                                        "dlSubdir": "N\u001a/\u001b",-                                        "dlTag": [-                                            "Latest",-                                            "Recommended",-                                            "Recommended",-                                            "\u0001)CZ/c",-                                            "old",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:hq"-                                    },-                                    "( <= 1.3.3 && >= 4.3.1 && == 3.1.2 && > 2.1.5 && < 3.2.2 )": {-                                        "dlCSize": 1,-                                        "dlHash": "chdtrzq",-                                        "dlOutput": "3\"",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "Latest"-                                        ],-                                        "dlUri": "https:u"-                                    },-                                    "( == 2.3.4 && == 3.3.5 && <= 2.3.5 && <= 5.3.3 )": {-                                        "dlCSize": -6,-                                        "dlHash": "furc",-                                        "dlOutput": "JUm<",-                                        "dlSubdir": "\u001a𫐣x",-                                        "dlTag": null,-                                        "dlUri": "http:a"-                                    },-                                    "( > 2.2.4 && >= 4.3.5 && >= 5.5.5 && > 2.5.4 && == 5.2.3 && == 1.3.1 && >= 1.5.3 )": {-                                        "dlCSize": 3,-                                        "dlHash": "jt",-                                        "dlOutput": "\u001b󱾧'舶󳒽,",-                                        "dlSubdir": "\u000c𩣋",-                                        "dlTag": [],-                                        "dlUri": "https:rnfa"-                                    },-                                    "( >= 4.2.1 && > 2.4.2 && <= 2.5.1 && >= 2.1.2 && >= 2.5.2 && >= 2.2.2 && > 2.2.5 ) || ( == 3.2.1 && < 4.3.2 && < 1.4.4 )": {-                                        "dlCSize": -1,-                                        "dlHash": "dfta",-                                        "dlOutput": "\u0017",-                                        "dlSubdir": {-                                            "RegexDir": "𨃪"-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "Nightly",-                                            "Nightly",-                                            "Nightly",-                                            "Nightly",-                                            "Latest",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:xfynvdl"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -1,-                                        "dlHash": "hbdgra",-                                        "dlOutput": "㇇磰󰿛aKow",-                                        "dlSubdir": "􈗐",-                                        "dlTag": null,-                                        "dlUri": "http:vekerca"-                                    }-                                },-                                "FreeBSD": {-                                    "( <= 1.2.2 && < 3.1.1 && <= 2.4.4 && <= 4.3.2 )": {-                                        "dlCSize": 3,-                                        "dlHash": "ekeyafu",-                                        "dlOutput": "k𨡂c􂮚",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestNightly",-                                            "base-1.1.5",-                                            "Latest",-                                            "Recommended",-                                            "Experimental",-                                            "Recommended",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:nde"-                                    }-                                }-                            },-                            "A_64": {-                                "Windows": {}-                            },-                            "A_ARM64": {-                                "FreeBSD": {-                                    "( < 5.3.3 && > 4.1.1 && <= 1.2.3 && == 2.2.2 && > 4.5.5 && == 1.3.1 && > 4.4.4 ) || ( > 2.1.5 && > 2.3.3 && >= 1.2.2 && >= 1.2.3 && == 1.1.2 && > 3.2.3 )": {-                                        "dlCSize": 3,-                                        "dlHash": "werav",-                                        "dlOutput": "\u0011\u0016􀙎g膬𩰖\u0005",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:"-                                    },-                                    "( <= 2.3.4 ) || ( > 1.1.1 && < 3.2.1 && <= 4.2.2 && == 1.4.1 )": {-                                        "dlCSize": -1,-                                        "dlHash": "sz",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "}Q\u0018\u0007"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "LatestNightly",-                                            "base-5.3.2",-                                            "LatestPrerelease",-                                            "Recommended",-                                            "LatestNightly",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:xz"-                                    },-                                    "( == 2.4.2 && >= 1.4.1 ) || ( < 2.2.1 && == 2.2.4 && == 2.3.4 && >= 1.2.2 && >= 1.2.2 )": {-                                        "dlCSize": 0,-                                        "dlHash": "",-                                        "dlOutput": "",-                                        "dlSubdir": "\u0000\u0010\u0005k𦸙",-                                        "dlTag": [-                                            "base-6.3.5",-                                            "Experimental",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:smwo"-                                    },-                                    "( >= 5.5.1 && < 4.3.1 )": {-                                        "dlCSize": -1,-                                        "dlHash": "fikxfg",-                                        "dlOutput": "訁\u000bv",-                                        "dlSubdir": {-                                            "RegexDir": "󷞂;"-                                        },-                                        "dlTag": [-                                            "Experimental"-                                        ],-                                        "dlUri": "https:okv"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -7,-                                        "dlHash": "",-                                        "dlOutput": "𪳃􅴟K󷟗",-                                        "dlSubdir": "𛃆I\u0011",-                                        "dlTag": [-                                            "Prerelease",-                                            "LatestNightly",-                                            "LatestNightly",-                                            "Latest"-                                        ],-                                        "dlUri": "https:jhhyfrj"-                                    }-                                },-                                "Windows": {-                                    "( < 4.3.2 && == 2.2.5 && > 3.1.4 )": {-                                        "dlCSize": 2,-                                        "dlHash": "vrh",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease",-                                            "base-5.5.5",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( == 3.2.2 && == 2.1.3 && < 2.3.5 && > 2.2.2 && == 4.4.2 && == 4.5.2 && > 5.5.2 )": {-                                        "dlCSize": 6,-                                        "dlHash": "ggm",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "https:x"-                                    },-                                    "( == 3.4.5 && >= 4.2.2 && < 1.5.4 && <= 3.2.3 && < 4.5.3 && > 3.5.1 ) || ( == 4.3.1 ) || ( < 3.4.3 )": {-                                        "dlCSize": 2,-                                        "dlHash": "lnwhgvq",-                                        "dlOutput": "wF怕\u0008",-                                        "dlSubdir": "\u0005K􇞚ᆲ",-                                        "dlTag": [-                                            "Prerelease",-                                            "Latest",-                                            "base-3.6.4"-                                        ],-                                        "dlUri": "http:yovtdoc"-                                    },-                                    "( == 3.5.5 && < 2.4.4 && < 4.2.5 && > 5.2.3 && == 4.5.1 && < 5.2.3 && < 4.6.2 ) || ( < 4.1.1 && == 1.1.3 ) || ( >= 2.2.1 && == 3.4.2 && >= 3.1.3 )": {-                                        "dlCSize": 5,-                                        "dlHash": "rebswlw",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "􌒛𪾙"-                                        },-                                        "dlTag": [-                                            "Recommended",-                                            "old",-                                            "Prerelease",-                                            "Recommended",-                                            "LatestPrerelease",-                                            "Latest"-                                        ],-                                        "dlUri": "https:s"-                                    },-                                    "( > 4.2.4 && == 4.3.5 && > 4.1.1 && == 3.5.5 && < 4.1.5 && <= 4.2.2 )": {-                                        "dlCSize": -5,-                                        "dlHash": "g",-                                        "dlOutput": ":􅽷🎉.9𫣸",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "Latest",-                                            "old",-                                            "base-5.1.6"-                                        ],-                                        "dlUri": "https:m"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 3,-                                        "dlHash": "qgrl",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "v/䊪"-                                        },-                                        "dlTag": [-                                            "base-5.4.5",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:pjk"-                                    }-                                }-                            },-                            "A_PowerPC": {-                                "Darwin": {-                                    "( > 6.5.4 && < 5.5.5 && == 3.5.1 && <= 2.4.2 && >= 3.1.2 && <= 2.5.5 && > 4.3.1 ) || ( > 3.2.4 )": {-                                        "dlCSize": 0,-                                        "dlHash": "rdxytxc",-                                        "dlOutput": "i3",-                                        "dlSubdir": "rE~𦁵aR",-                                        "dlTag": [-                                            "Prerelease",-                                            "Prerelease",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:zbi"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -7,-                                        "dlHash": "azttl",-                                        "dlOutput": ".𩇭𛋂\u001d\u0011k",-                                        "dlSubdir": "􉁋VLS",-                                        "dlTag": null,-                                        "dlUri": "http:ta"-                                    }-                                },-                                "FreeBSD": {-                                    "( > 2.3.6 && < 4.4.5 && <= 1.3.2 && <= 3.5.5 && > 1.2.5 ) || ( <= 3.3.4 && == 4.4.2 )": {-                                        "dlCSize": -5,-                                        "dlHash": "nyxr",-                                        "dlOutput": "􃡑\u0017w]",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-5.1.4",-                                            "Recommended",-                                            "old",-                                            "Recommended",-                                            "Latest",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:dwir"-                                    }-                                },-                                "Linux_CentOS": {-                                    "( < 5.2.3 && >= 2.4.3 && == 3.2.1 && <= 2.4.4 )": {-                                        "dlCSize": 4,-                                        "dlHash": "ynscxjs",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:uy"-                                    }-                                },-                                "Windows": {-                                    "( <= 1.5.3 && <= 4.3.4 && >= 5.2.2 )": {-                                        "dlCSize": 0,-                                        "dlHash": "adgj",-                                        "dlOutput": null,-                                        "dlSubdir": "`p\u0010*",-                                        "dlTag": [-                                            "Nightly",-                                            "LatestNightly",-                                            "LatestPrerelease",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:ze"-                                    },-                                    "( <= 4.1.3 ) || ( < 1.2.3 && < 4.4.3 && > 2.4.4 && <= 4.1.1 && == 5.4.4 ) || ( > 2.2.2 && == 2.1.2 && <= 2.2.2 && == 1.1.2 && == 3.2.1 ) || ( > 2.1.1 ) || ( >= 1.2.1 && == 2.1.1 && >= 2.2.1 ) || ( == 1.1.2 ) || ( < 1.1.1 ) || ( < 1.1.2 )": {-                                        "dlCSize": 7,-                                        "dlHash": "obkwyw",-                                        "dlOutput": "G𬤫",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-5.3.2",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:nzv"-                                    },-                                    "( <= 4.5.1 && >= 5.4.4 && < 5.2.4 && >= 4.3.1 && >= 4.1.4 ) || ( > 4.1.2 && <= 5.4.4 && <= 5.2.1 && <= 3.3.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "ezstbf",-                                        "dlOutput": "\u000b",-                                        "dlSubdir": {-                                            "RegexDir": "{,󴩔h\u000c𠞗"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:x"-                                    },-                                    "( <= 5.5.4 && <= 4.4.4 && >= 4.5.4 && >= 4.3.4 && > 3.4.2 ) || ( >= 2.4.3 && > 1.2.1 && >= 2.3.4 && > 3.3.2 && >= 1.1.1 && >= 3.1.1 )": {-                                        "dlCSize": 1,-                                        "dlHash": "cik",-                                        "dlOutput": "hէ_\u001e>",-                                        "dlSubdir": "",-                                        "dlTag": null,-                                        "dlUri": "http:pzgavmr"-                                    },-                                    "( > 2.1.2 )": {-                                        "dlCSize": 2,-                                        "dlHash": "puakriv",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Nightly",-                                            "base-6.3.1",-                                            "LatestPrerelease",-                                            "Nightly",-                                            "Prerelease",-                                            "LatestNightly",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:f"-                                    },-                                    "( > 2.1.4 ) || ( >= 4.4.3 && < 2.3.4 ) || ( == 3.3.2 && < 1.2.3 )": {-                                        "dlCSize": 1,-                                        "dlHash": "qzktr",-                                        "dlOutput": ")/",-                                        "dlSubdir": "s1+",-                                        "dlTag": null,-                                        "dlUri": "https:tm"-                                    },-                                    "( >= 5.2.2 )": {-                                        "dlCSize": -1,-                                        "dlHash": "hcpqq",-                                        "dlOutput": "N=\u001f먒r󳰮\u0013",-                                        "dlSubdir": {-                                            "RegexDir": "􅃻t\u0000蓜Q\u001d"-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "base-4.5.4",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:vuog"-                                    }-                                }-                            },-                            "A_Sparc": {-                                "Darwin": {},-                                "FreeBSD": {-                                    "( < 4.2.2 && == 1.1.5 && <= 4.1.5 )": {-                                        "dlCSize": 5,-                                        "dlHash": "bxtx",-                                        "dlOutput": "󲑳%.\u0014",-                                        "dlSubdir": "Z~\"\u001a",-                                        "dlTag": [-                                            "Prerelease",-                                            "Prerelease",-                                            "Latest",-                                            "Experimental",-                                            "\u0000P浙",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:xqbxr"-                                    },-                                    "( <= 1.2.1 && < 4.3.4 && == 2.4.3 && <= 1.1.2 && < 5.5.4 && == 2.3.4 )": {-                                        "dlCSize": 5,-                                        "dlHash": "z",-                                        "dlOutput": "\u0000\u000c􂕁\u000c𞤔OC",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:u"-                                    },-                                    "( <= 4.5.6 && <= 5.3.3 && < 6.2.2 && >= 4.3.1 && >= 3.2.3 && >= 4.4.1 ) || ( < 4.4.2 && >= 2.1.3 && < 1.1.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "jldpyjf",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "https:xs"-                                    },-                                    "( == 5.4.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "skv",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "𫜚𗣘𰇴\r"-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "Latest",-                                            "Recommended",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:wytt"-                                    },-                                    "( >= 1.4.3 && > 1.3.2 && == 2.3.3 && < 5.3.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": "[Ḛ\"ꙁ]&",-                                        "dlSubdir": {-                                            "RegexDir": "G-6I"-                                        },-                                        "dlTag": [],-                                        "dlUri": "http:ffu"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "tc",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease",-                                            "Latest",-                                            "old",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:rlqh"-                                    }-                                }-                            }-                        },-                        "viChangeLog": "https:dyjcf",-                        "viPostInstall": "",-                        "viPostRemove": "d",-                        "viPreCompile": null,-                        "viPreInstall": "gavk",-                        "viReleaseDay": "7052234926266086-04-11",-                        "viSourceDL": null,-                        "viTags": [-                            "LatestPrerelease",-                            "Latest",-                            "old"-                        ],-                        "viTestDL": {-                            "dlCSize": 2,-                            "dlHash": "",-                            "dlOutput": null,-                            "dlSubdir": {-                                "RegexDir": "=\u0015"-                            },-                            "dlTag": [-                                "\u0013𢮪"-                            ],-                            "dlUri": "http:jtjl"-                        }-                    }-                },-                "GHC": {-                    "1.7.5": {-                        "viArch": {-                            "A_32": {-                                "FreeBSD": {-                                    "( < 3.4.1 && >= 1.3.5 && >= 3.2.2 ) || ( > 5.3.1 && >= 5.4.2 && < 1.3.2 && == 2.1.1 && > 3.1.3 )": {-                                        "dlCSize": -7,-                                        "dlHash": "yk",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "7"-                                        },-                                        "dlTag": [-                                            "old",-                                            "􄘝DSv",-                                            "LatestNightly",-                                            "Nightly",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:eiutp"-                                    },-                                    "( <= 3.4.2 && == 5.2.4 && <= 2.4.2 ) || ( <= 4.1.2 && == 4.3.1 && < 2.4.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "n",-                                        "dlOutput": "s",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-4.6.6",-                                            "Nightly",-                                            "base-4.4.6",-                                            "old",-                                            "Nightly",-                                            "base-1.5.3",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:u"-                                    },-                                    "( <= 4.2.2 && < 2.5.1 ) || ( > 1.1.2 ) || ( <= 3.3.2 && > 3.1.1 && < 2.1.3 && <= 2.2.2 && > 3.3.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "blynrzb",-                                        "dlOutput": "a\u0018수",-                                        "dlSubdir": {-                                            "RegexDir": "mv"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:rffusb"-                                    },-                                    "( <= 4.6.1 && == 2.2.2 && == 3.4.1 && <= 5.2.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "i",-                                        "dlOutput": "R<h|",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease",-                                            "LatestNightly",-                                            "Recommended",-                                            "Nightly",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:pcuxudk"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 0,-                                        "dlHash": "foabv",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "https:jvyjadv"-                                    }-                                },-                                "Linux_AmazonLinux": {-                                    "( > 1.1.4 && == 1.2.5 && < 3.5.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "c",-                                        "dlOutput": "􎚍\u001ep:􂃮d",-                                        "dlSubdir": "z\u0012\u001d",-                                        "dlTag": [-                                            "Prerelease",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:fdvsqf"-                                    },-                                    "( > 1.5.5 ) || ( < 3.1.3 && < 1.1.3 && < 2.2.1 && == 3.2.1 && == 2.2.3 ) || ( >= 1.3.1 && == 1.1.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "mxihzdr",-                                        "dlOutput": "󸉈\u0018\u0000𣵡󽚂\r",-                                        "dlSubdir": {-                                            "RegexDir": "\u001e"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:qpxt"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 2,-                                        "dlHash": "wqpzyb",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:grswle"-                                    }-                                },-                                "Linux_RedHat": {-                                    "( == 3.4.4 && < 3.4.2 && < 1.2.3 && < 2.1.1 && <= 4.5.3 && < 4.4.1 && >= 3.1.2 )": {-                                        "dlCSize": -5,-                                        "dlHash": "fnlyzbk",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "?䢙\u0000^􀘉P"-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "Recommended",-                                            "Recommended",-                                            "Recommended",-                                            "Recommended",-                                            "Prerelease",-                                            "Latest"-                                        ],-                                        "dlUri": "https:sz"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "dncid",-                                        "dlOutput": "*|7\u001e%\u0012",-                                        "dlSubdir": {-                                            "RegexDir": "Y"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:j"-                                    }-                                },-                                "Linux_Void": {-                                    "( >= 3.1.3 && <= 3.1.5 && > 3.3.4 )": {-                                        "dlCSize": -4,-                                        "dlHash": "ldzizyk",-                                        "dlOutput": ":2H𱻼]󰒛󺽪",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-2.1.2",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:kvfkto"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -6,-                                        "dlHash": "etjj",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Latest",-                                            "base-6.3.5"-                                        ],-                                        "dlUri": "http:dxpxgf"-                                    }-                                }-                            },-                            "A_64": {-                                "FreeBSD": {-                                    "( > 1.1.3 ) || ( < 2.4.4 )": {-                                        "dlCSize": -6,-                                        "dlHash": "sgalrjz",-                                        "dlOutput": "畩\u0001",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "https:ovwq"-                                    },-                                    "( >= 1.3.5 && < 4.4.2 && > 3.2.3 && <= 4.3.3 && >= 3.5.3 && > 1.1.2 ) || ( <= 2.3.1 && < 4.1.1 && < 2.2.1 && >= 3.1.1 && == 2.4.2 )": {-                                        "dlCSize": -4,-                                        "dlHash": "xach",-                                        "dlOutput": "\u0014𫨰Y",-                                        "dlSubdir": {-                                            "RegexDir": "K3੶]𨕵"-                                        },-                                        "dlTag": [-                                            "Latest",-                                            "Latest",-                                            "old",-                                            "Latest",-                                            "LatestPrerelease",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:jnv"-                                    },-                                    "( >= 2.4.4 && >= 2.5.3 && < 5.3.1 && >= 3.2.4 && < 4.1.4 && < 4.3.2 && <= 2.1.5 )": {-                                        "dlCSize": 2,-                                        "dlHash": "gukto",-                                        "dlOutput": "\\a\u0019C^\u0019",-                                        "dlSubdir": {-                                            "RegexDir": "󷈎\"m􉶤"-                                        },-                                        "dlTag": [-                                            ":u",-                                            "old"-                                        ],-                                        "dlUri": "https:dolnvh"-                                    },-                                    "( >= 5.4.2 && <= 2.5.4 && < 2.5.5 && > 2.2.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "j",-                                        "dlOutput": "B27",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-1.4.5",-                                            "Recommended",-                                            "Nightly",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:sxtq"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 4,-                                        "dlHash": "fupmm",-                                        "dlOutput": "m𔓱p",-                                        "dlSubdir": {-                                            "RegexDir": "\u0013hU랦8󲁪"-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:i"-                                    }-                                },-                                "Linux_Ubuntu": {-                                    "( < 2.4.5 && < 1.2.2 && <= 2.1.1 && <= 4.1.2 && >= 3.4.3 && >= 1.4.2 && < 4.2.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "ergg",-                                        "dlOutput": "𫉭/&\u000b",-                                        "dlSubdir": {-                                            "RegexDir": "\u0005\u0001a"-                                        },-                                        "dlTag": [-                                            "Recommended",-                                            "Latest",-                                            "Nightly",-                                            "base-5.6.2",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:dhwvqpj"-                                    },-                                    "( == 2.4.3 )": {-                                        "dlCSize": -2,-                                        "dlHash": "z",-                                        "dlOutput": "\u0013㏳f\r",-                                        "dlSubdir": "Z􊻧硱r󵦃_",-                                        "dlTag": [-                                            "dL3W5G",-                                            "old",-                                            "􋋭r)b|",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:yxzkln"-                                    },-                                    "( == 4.4.4 && > 3.5.4 && > 1.1.2 ) || ( <= 3.3.4 && > 1.4.3 && > 1.2.1 && <= 1.1.1 ) || ( == 3.3.1 && == 3.1.3 && > 4.2.3 && < 1.2.1 && == 3.1.2 )": {-                                        "dlCSize": 7,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "􉭚󵳁󷛭"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:ixwet"-                                    },-                                    "( == 6.5.2 && < 2.4.6 && > 1.3.4 ) || ( > 1.4.1 && == 2.4.2 )": {-                                        "dlCSize": 5,-                                        "dlHash": "dihps",-                                        "dlOutput": "",-                                        "dlSubdir": "T\u0014𰊨􏎤",-                                        "dlTag": [],-                                        "dlUri": "http:hdtlc"-                                    },-                                    "( > 1.2.2 && >= 4.3.1 && <= 2.3.1 && >= 5.4.4 )": {-                                        "dlCSize": -1,-                                        "dlHash": "omlhepu",-                                        "dlOutput": "z\t=:",-                                        "dlSubdir": {-                                            "RegexDir": "[F.\ra"-                                        },-                                        "dlTag": [-                                            "",-                                            "Latest",-                                            "Recommended",-                                            "Latest",-                                            "i",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( > 1.3.5 && >= 4.3.5 && >= 1.2.1 && >= 3.4.1 && >= 2.1.3 && > 4.4.5 ) || ( < 1.1.1 && < 4.1.4 && <= 2.4.2 && < 1.1.4 )": {-                                        "dlCSize": 2,-                                        "dlHash": "",-                                        "dlOutput": "M𠾉㪋oM-",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Latest",-                                            "Prerelease",-                                            "base-3.2.3",-                                            "LatestNightly",-                                            "Nightly",-                                            "old"-                                        ],-                                        "dlUri": "http:pokv"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "fierm",-                                        "dlOutput": "?\u0011UI􂻷x슆",-                                        "dlSubdir": {-                                            "RegexDir": "\\#\u0005\\"-                                        },-                                        "dlTag": [-                                            "x",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:m"-                                    }-                                },-                                "Windows": {-                                    "( <= 1.2.2 ) || ( < 2.3.3 && == 3.3.2 && >= 2.1.3 && >= 2.3.3 && < 3.3.2 && >= 4.1.1 )": {-                                        "dlCSize": -2,-                                        "dlHash": "ozlcxn",-                                        "dlOutput": "]5𮚍",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "http:eddvv"-                                    },-                                    "( <= 2.6.3 )": {-                                        "dlCSize": -7,-                                        "dlHash": "ujeeq",-                                        "dlOutput": "f􋁻4\u0001\u0014󵱮󵟋",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:zpucd"-                                    },-                                    "( <= 3.3.3 && < 4.4.3 && > 3.4.5 && == 3.1.4 && == 2.4.4 && <= 5.2.1 ) || ( == 4.1.4 && == 1.2.4 ) || ( == 2.2.1 && > 1.1.3 && < 3.1.2 && >= 2.3.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "qws",-                                        "dlOutput": null,-                                        "dlSubdir": "􈎥􎑅",-                                        "dlTag": [-                                            "Experimental",-                                            "1🁅􃶞2",-                                            "base-5.4.5",-                                            "old"-                                        ],-                                        "dlUri": "http:telxeu"-                                    },-                                    "( >= 4.5.5 && >= 1.4.1 && <= 2.3.4 && <= 2.2.2 && == 1.2.3 ) || ( <= 1.4.3 && == 1.3.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "xhvsoi",-                                        "dlOutput": "\u0015\u0008\u0008]\u0002K􄹨",-                                        "dlSubdir": "\u0014r\u000e",-                                        "dlTag": [],-                                        "dlUri": "http:slifh"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -3,-                                        "dlHash": "dwx",-                                        "dlOutput": "s\u0004𡜜\n\u0015h",-                                        "dlSubdir": {-                                            "RegexDir": "\u0011"-                                        },-                                        "dlTag": [],-                                        "dlUri": "http:"-                                    }-                                }-                            },-                            "A_ARM": {-                                "Darwin": {-                                    "( <= 2.3.3 && <= 1.4.4 && > 2.2.5 && > 3.2.5 && <= 3.5.2 )": {-                                        "dlCSize": -6,-                                        "dlHash": "cmyj",-                                        "dlOutput": "j ",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:h"-                                    }-                                },-                                "FreeBSD": {-                                    "( <= 5.2.1 && <= 1.1.4 && == 3.4.4 )": {-                                        "dlCSize": 5,-                                        "dlHash": "jo",-                                        "dlOutput": "p𣨮펰𬵾?𘈅􁧭",-                                        "dlSubdir": "&%aH",-                                        "dlTag": null,-                                        "dlUri": "https:e"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 1,-                                        "dlHash": "o",-                                        "dlOutput": "𩎐h_h0\u001e ",-                                        "dlSubdir": "$?b𠽏m",-                                        "dlTag": [-                                            "base-2.2.1",-                                            "Latest",-                                            "Nightly",-                                            "\u0008\u00128\u001c",-                                            "Prerelease",-                                            "Prerelease",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:itah"-                                    }-                                },-                                "Windows": {-                                    "( < 1.2.2 && > 1.5.5 && < 3.5.3 && == 4.4.4 && >= 5.5.5 && == 3.1.3 && > 3.5.3 ) || ( < 3.1.1 && > 3.2.1 && <= 2.1.3 && == 3.4.4 && <= 2.2.3 ) || ( == 1.1.1 && > 3.1.1 )": {-                                        "dlCSize": 5,-                                        "dlHash": "wdgz",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:hzt"-                                    },-                                    "( < 1.3.1 && < 4.5.1 && == 5.4.2 && == 5.2.4 && > 2.3.1 ) || ( < 4.2.1 ) || ( >= 3.3.1 && >= 1.2.4 && <= 1.3.1 )": {-                                        "dlCSize": 7,-                                        "dlHash": "mai",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "#"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "old",-                                            "l5{",-                                            "base-6.1.4",-                                            "𭘡W",-                                            "LatestNightly",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:wigby"-                                    },-                                    "( < 3.2.4 && == 2.3.5 && == 1.3.1 && >= 4.2.5 && < 3.1.5 && <= 5.2.2 ) || ( <= 2.4.4 && >= 4.2.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "gwqsk",-                                        "dlOutput": "ﱖ/",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "old",-                                            "Latest",-                                            "Latest",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:te"-                                    },-                                    "( < 4.5.3 && <= 2.2.3 && <= 3.5.4 ) || ( == 1.2.2 && < 2.1.1 )": {-                                        "dlCSize": 7,-                                        "dlHash": "q",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:ltyquir"-                                    },-                                    "( < 5.3.3 && < 3.3.1 && < 2.1.2 && == 2.2.1 && < 1.4.2 && == 1.5.1 && < 4.4.1 ) || ( > 4.1.4 && >= 2.2.3 )": {-                                        "dlCSize": 3,-                                        "dlHash": "lvzr",-                                        "dlOutput": null,-                                        "dlSubdir": "Z",-                                        "dlTag": [-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:ntry"-                                    },-                                    "( == 4.3.1 && >= 1.5.4 && == 5.1.1 && == 3.1.3 && == 5.2.4 && >= 1.4.5 && < 3.3.1 )": {-                                        "dlCSize": -4,-                                        "dlHash": "",-                                        "dlOutput": "29?0.",-                                        "dlSubdir": "\u00175W[",-                                        "dlTag": [-                                            "Prerelease",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:skh"-                                    },-                                    "( >= 5.5.2 && == 3.2.5 && < 3.1.5 ) || ( >= 1.3.1 ) || ( >= 1.1.2 && < 3.2.3 ) || ( >= 1.1.2 && > 1.2.2 && >= 2.2.1 ) || ( <= 1.1.2 ) || ( > 1.1.1 )": {-                                        "dlCSize": -7,-                                        "dlHash": "ve",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:ylmv"-                                    }-                                }-                            },-                            "A_ARM64": {-                                "Darwin": {},-                                "FreeBSD": {-                                    "( < 2.1.5 && <= 5.5.4 && <= 5.4.5 && < 1.3.5 && <= 2.2.1 && < 2.3.2 && > 4.4.3 ) || ( <= 2.3.2 && > 2.1.1 && >= 1.4.4 && >= 1.4.2 ) || ( <= 3.1.4 && > 1.1.1 && == 3.3.1 && > 2.2.3 )": {-                                        "dlCSize": 3,-                                        "dlHash": "cckguou",-                                        "dlOutput": "D(\u000ei",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "Recommended",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "( <= 3.4.1 && < 2.3.5 && > 2.5.5 && < 4.4.2 && > 5.2.5 && == 4.5.4 && > 4.2.2 ) || ( >= 3.4.3 && == 4.5.4 && == 3.1.2 && == 1.3.2 && > 1.1.2 && > 4.2.4 )": {-                                        "dlCSize": 7,-                                        "dlHash": "qmlkr",-                                        "dlOutput": null,-                                        "dlSubdir": " 􀗆󶢛F",-                                        "dlTag": null,-                                        "dlUri": "http:djpxgn"-                                    },-                                    "( == 5.2.2 && <= 3.4.4 && < 1.2.3 && > 3.4.2 && > 3.5.2 && < 1.1.5 ) || ( > 2.3.1 && == 3.3.2 ) || ( < 1.1.1 && == 2.4.1 && >= 2.1.1 && > 2.1.1 && <= 3.2.1 )": {-                                        "dlCSize": 3,-                                        "dlHash": "",-                                        "dlOutput": "\u001f􅡒",-                                        "dlSubdir": "",-                                        "dlTag": null,-                                        "dlUri": "https:hawid"-                                    },-                                    "( == 5.3.1 && > 2.5.5 && < 2.4.4 && == 3.5.1 ) || ( == 4.5.1 && <= 3.5.1 && == 4.1.4 && >= 1.4.3 && <= 3.1.1 ) || ( == 1.3.4 && > 2.1.2 && <= 3.2.1 && == 2.3.1 )": {-                                        "dlCSize": -1,-                                        "dlHash": "",-                                        "dlOutput": "\u0015􎛖G",-                                        "dlSubdir": "􆩄uuᄓZ𰩴",-                                        "dlTag": [-                                            "Experimental",-                                            "Experimental",-                                            "LatestPrerelease",-                                            "🌌D𱸂gJ🔪"-                                        ],-                                        "dlUri": "http:nbyzp"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -3,-                                        "dlHash": "t",-                                        "dlOutput": "_3`\u000e켦\t",-                                        "dlSubdir": "􍘈9W𛇨",-                                        "dlTag": [-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:loi"-                                    }-                                },-                                "Linux_RedHat": {-                                    "( == 4.1.2 && < 4.4.3 && <= 2.3.2 && >= 3.5.4 && > 2.3.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": "\u0019뵫",-                                        "dlTag": [-                                            "",-                                            "+-󻑪",-                                            "Nightly",-                                            "old",-                                            "Prerelease",-                                            "\u0016䃛",-                                            "base-1.3.5"-                                        ],-                                        "dlUri": "http:fvwyan"-                                    },-                                    "( > 5.2.2 && < 2.4.4 && < 4.3.1 && <= 1.3.1 && >= 5.4.5 && < 2.4.4 && > 4.2.3 ) || ( <= 4.5.1 ) || ( >= 3.2.1 && > 3.3.3 && <= 1.1.3 && >= 2.3.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "yv",-                                        "dlOutput": "YY->\u0014",-                                        "dlSubdir": {-                                            "RegexDir": "\u0006+𨘂Q,"-                                        },-                                        "dlTag": [-                                            "/Sp|",-                                            "",-                                            "Latest",-                                            "old"-                                        ],-                                        "dlUri": "http:gsrodgd"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 3,-                                        "dlHash": "",-                                        "dlOutput": "󺩿FI",-                                        "dlSubdir": "𮩩\u0017s",-                                        "dlTag": null,-                                        "dlUri": "http:rmep"-                                    }-                                },-                                "Windows": {-                                    "( < 6.2.4 && > 2.1.2 && <= 1.6.3 && == 5.1.5 && <= 2.5.1 ) || ( > 4.4.2 && <= 2.4.2 && >= 4.3.4 && <= 3.1.3 && == 1.1.4 && >= 3.2.2 )": {-                                        "dlCSize": -6,-                                        "dlHash": "",-                                        "dlOutput": "􊿻𰖕\u0002\u001f󱇼𡹞",-                                        "dlSubdir": "\u0014e\u0016𫢺",-                                        "dlTag": [-                                            "Experimental",-                                            "old",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:kpdecs"-                                    }-                                }-                            },-                            "A_PowerPC": {},-                            "A_Sparc64": {-                                "Darwin": {},-                                "FreeBSD": {-                                    "( < 4.1.4 && == 4.2.1 ) || ( < 2.3.1 && >= 2.4.1 && == 1.4.3 && < 3.3.2 && >= 4.4.3 ) || ( == 2.2.2 && > 3.1.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": "\u001d\u00135|$",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:qvee"-                                    },-                                    "( == 3.5.4 && == 2.4.2 && == 3.2.1 && >= 2.3.1 && <= 2.5.2 && > 1.2.1 && <= 4.5.3 )": {-                                        "dlCSize": -1,-                                        "dlHash": "acl",-                                        "dlOutput": "H",-                                        "dlSubdir": "d\u0017茁\u0018A",-                                        "dlTag": [-                                            "Recommended",-                                            "Nightly",-                                            "base-5.1.1",-                                            "Experimental",-                                            "base-4.5.6",-                                            "Nightly",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:zg"-                                    }-                                },-                                "Linux_Gentoo": {-                                    "( <= 2.2.3 && == 5.5.4 && > 4.5.5 && == 3.3.4 )": {-                                        "dlCSize": 2,-                                        "dlHash": "",-                                        "dlOutput": "v)n~",-                                        "dlSubdir": {-                                            "RegexDir": "G\u0003x>r"-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "\u0015d1\u0003\u001c󹢥"-                                        ],-                                        "dlUri": "http:sfmhqa"-                                    },-                                    "( >= 5.4.3 && == 1.1.1 && < 3.5.2 && > 1.3.5 && > 2.3.1 && == 2.2.4 && > 1.3.3 ) || ( < 1.1.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "syzdckt",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "્]"-                                        },-                                        "dlTag": [-                                            "base-6.6.1",-                                            "Prerelease",-                                            "Nightly",-                                            "base-2.3.2"-                                        ],-                                        "dlUri": "http:zk"-                                    }-                                },-                                "Windows": {-                                    "( < 3.4.5 && <= 5.3.1 && <= 2.5.5 && > 4.5.2 && > 2.4.4 && <= 2.1.1 )": {-                                        "dlCSize": -4,-                                        "dlHash": "gspd",-                                        "dlOutput": "xY􁑭W󷁿\u0016󷭭",-                                        "dlSubdir": "\u001b\u0017",-                                        "dlTag": [-                                            "old",-                                            "Recommended",-                                            "Latest",-                                            "LatestPrerelease",-                                            "Nightly",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:efn"-                                    },-                                    "( <= 2.1.4 && <= 5.3.1 && > 3.3.3 )": {-                                        "dlCSize": -5,-                                        "dlHash": "hhl",-                                        "dlOutput": "\u000c\u0000􂴞",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "base-3.3.5",-                                            "base-4.3.5",-                                            "LatestPrerelease",-                                            "Experimental",-                                            "Recommended",-                                            "\u0017󷇆",-                                            "Latest"-                                        ],-                                        "dlUri": "http:abzbu"-                                    },-                                    "( == 1.3.2 && < 5.5.5 && > 3.4.2 && > 4.5.5 && == 3.2.5 ) || ( <= 1.1.4 && > 1.4.4 && < 2.4.4 && == 3.3.3 )": {-                                        "dlCSize": 3,-                                        "dlHash": "srtjnr",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "𢢾$`T"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "Latest",-                                            "old",-                                            "\u0012:Uf",-                                            "LatestPrerelease",-                                            "old"-                                        ],-                                        "dlUri": "https:ggx"-                                    }-                                }-                            }-                        },-                        "viChangeLog": "https:wz",-                        "viPostInstall": null,-                        "viPostRemove": null,-                        "viPreCompile": "",-                        "viPreInstall": null,-                        "viReleaseDay": "19388636140044521-07-03",-                        "viSourceDL": null,-                        "viTags": [-                            "Nightly"-                        ],-                        "viTestDL": {-                            "dlCSize": 0,-                            "dlHash": "rka",-                            "dlOutput": null,-                            "dlSubdir": "e.",-                            "dlTag": [-                                "Nightly"-                            ],-                            "dlUri": "https:mb"-                        }-                    },-                    "2.1.6": {-                        "viArch": {-                            "A_64": {-                                "Darwin": {-                                    "( <= 4.3.1 && == 4.1.4 && < 5.1.3 && >= 1.3.2 ) || ( == 2.4.4 ) || ( > 3.3.1 )": {-                                        "dlCSize": 7,-                                        "dlHash": "lugsea",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:pnitofk"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 3,-                                        "dlHash": "paw",-                                        "dlOutput": "󴚈풗x",-                                        "dlSubdir": {-                                            "RegexDir": "𣟰"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "old",-                                            "LatestPrerelease",-                                            "old",-                                            "old"-                                        ],-                                        "dlUri": "http:c"-                                    }-                                },-                                "FreeBSD": {-                                    "( < 4.2.4 && > 1.1.5 && <= 1.1.3 && >= 5.5.4 && < 4.4.1 ) || ( < 3.4.4 && < 4.3.3 && <= 3.3.2 ) || ( < 3.3.1 && < 2.1.1 && > 2.1.2 ) || ( < 2.2.1 && >= 1.2.2 && < 1.3.1 && < 1.2.2 ) || ( > 1.1.1 && < 2.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "`Go۰\u0018"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:hxoz"-                                    },-                                    "( == 4.3.3 && >= 4.4.2 && > 4.4.2 && >= 3.4.3 && == 3.1.2 && <= 5.3.1 ) || ( >= 2.2.1 )": {-                                        "dlCSize": -2,-                                        "dlHash": "ybkov",-                                        "dlOutput": "􅾻",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    },-                                    "( > 5.5.4 && == 2.3.5 )": {-                                        "dlCSize": -4,-                                        "dlHash": "occ",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "XGW󽇧\u0018",-                                            "Prerelease",-                                            "old",-                                            "Recommended",-                                            "LatestPrerelease",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:wvppqx"-                                    },-                                    "( >= 3.2.5 && >= 3.3.5 && == 2.3.5 && < 4.3.5 )": {-                                        "dlCSize": 4,-                                        "dlHash": "orqxwrd",-                                        "dlOutput": "",-                                        "dlSubdir": "\u0010~󹊧j>",-                                        "dlTag": [-                                            "Latest",-                                            "Nightly",-                                            "old",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:ei"-                                    },-                                    "( >= 5.3.5 && >= 4.3.4 && < 3.2.2 )": {-                                        "dlCSize": -6,-                                        "dlHash": "xtqch",-                                        "dlOutput": "\u001b",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Latest",-                                            "Latest",-                                            "Prerelease",-                                            "Latest"-                                        ],-                                        "dlUri": "https:sixkqt"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 5,-                                        "dlHash": "touzv",-                                        "dlOutput": "󻖗𮊫",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "Latest",-                                            "Prerelease",-                                            "Recommended",-                                            "LatestPrerelease",-                                            "base-4.2.3"-                                        ],-                                        "dlUri": "http:t"-                                    }-                                },-                                "Linux_Alpine": {-                                    "( < 1.2.3 && == 3.5.1 && < 2.4.5 && < 4.1.3 && < 4.4.5 && == 4.3.4 && == 2.3.2 )": {-                                        "dlCSize": 5,-                                        "dlHash": "aehyiak",-                                        "dlOutput": "󲦤",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:"-                                    },-                                    "( <= 2.5.5 && > 1.2.2 && >= 2.3.3 && >= 3.2.2 && >= 4.3.1 && <= 4.4.3 ) || ( == 2.1.2 && > 2.3.1 && >= 1.4.3 && < 2.3.4 && > 1.3.4 )": {-                                        "dlCSize": -7,-                                        "dlHash": "cviu",-                                        "dlOutput": "G;A󹰮𫈗s^",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "base-2.6.3",-                                            "Experimental",-                                            "old",-                                            "old",-                                            "Latest",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:rlyizgi"-                                    },-                                    "( <= 5.2.2 && < 2.2.3 && < 1.5.2 && == 3.4.3 && <= 3.1.4 )": {-                                        "dlCSize": 4,-                                        "dlHash": "fc",-                                        "dlOutput": "t}~",-                                        "dlSubdir": "􂐞𧞆𦂦",-                                        "dlTag": [-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:ai"-                                    },-                                    "( == 1.1.3 && <= 4.3.1 && <= 1.2.4 && >= 3.5.2 && < 5.3.4 && <= 3.1.1 && <= 5.2.3 ) || ( == 2.1.4 && > 2.2.2 ) || ( >= 3.2.1 && < 1.3.2 && <= 2.3.1 && > 2.2.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "iiqvsa",-                                        "dlOutput": "䄤",-                                        "dlSubdir": "ᄽ{D",-                                        "dlTag": [-                                            "Recommended",-                                            "base-1.5.5",-                                            "Recommended",-                                            "old",-                                            "|"-                                        ],-                                        "dlUri": "https:ebixwda"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -7,-                                        "dlHash": "khbbc",-                                        "dlOutput": "j",-                                        "dlSubdir": "",-                                        "dlTag": [],-                                        "dlUri": "https:"-                                    }-                                },-                                "Linux_Exherbo": {},-                                "Windows": {-                                    "( <= 2.3.2 && < 5.4.4 && <= 4.6.3 )": {-                                        "dlCSize": 5,-                                        "dlHash": "xkwuq",-                                        "dlOutput": "𛇚z(\u001a𧩸󿤷펁",-                                        "dlSubdir": "",-                                        "dlTag": null,-                                        "dlUri": "https:twvrehj"-                                    },-                                    "( <= 2.3.4 && < 3.3.2 && >= 2.2.5 && > 2.5.4 && > 2.5.2 )": {-                                        "dlCSize": -2,-                                        "dlHash": "nqd",-                                        "dlOutput": null,-                                        "dlSubdir": ";듏􇛮K\u0002",-                                        "dlTag": [-                                            "Latest",-                                            "Experimental",-                                            "Nightly",-                                            "LatestNightly",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:kwydvvb"-                                    },-                                    "( <= 2.3.6 && == 4.3.3 ) || ( < 2.4.3 && == 3.1.3 && > 3.2.4 && == 1.1.3 && >= 4.2.1 && < 3.2.4 )": {-                                        "dlCSize": 6,-                                        "dlHash": "tlaf",-                                        "dlOutput": "O(𦮀%",-                                        "dlSubdir": {-                                            "RegexDir": "}N("-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:tjqmsst"-                                    },-                                    "( == 2.1.3 && >= 1.4.4 ) || ( < 4.1.2 && < 3.3.3 && <= 1.4.2 && > 4.4.1 )": {-                                        "dlCSize": -7,-                                        "dlHash": "qtnxmv",-                                        "dlOutput": "\u000c🔥W/𮓫",-                                        "dlSubdir": "\u0017\u0007\u0013I􁟼E",-                                        "dlTag": [-                                            "LatestNightly",-                                            "Nightly",-                                            "LatestPrerelease",-                                            "Recommended",-                                            "Latest",-                                            "Latest"-                                        ],-                                        "dlUri": "https:m"-                                    },-                                    "( >= 5.2.1 && <= 1.5.4 && > 2.4.5 && < 5.1.3 && < 2.2.3 && <= 2.3.4 && < 3.2.1 )": {-                                        "dlCSize": 6,-                                        "dlHash": "e",-                                        "dlOutput": "1T\u0018󵰦\n",-                                        "dlSubdir": "\u0014",-                                        "dlTag": [-                                            "old",-                                            "LatestPrerelease",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:kv"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 6,-                                        "dlHash": "vtwmxs",-                                        "dlOutput": ")𦧍󹹪;C",-                                        "dlSubdir": "jL\u0001X",-                                        "dlTag": [-                                            "base-5.6.3",-                                            "LatestPrerelease",-                                            "Recommended",-                                            "old",-                                            "LatestPrerelease",-                                            "Prerelease",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:wjopdja"-                                    }-                                }-                            },-                            "A_ARM64": {-                                "FreeBSD": {-                                    "( <= 2.1.6 && == 1.3.2 && > 4.3.5 && > 4.4.3 && == 2.4.1 && < 3.1.4 && > 5.4.4 )": {-                                        "dlCSize": -3,-                                        "dlHash": "pgxg",-                                        "dlOutput": "T𢛹\u0001U􁿊",-                                        "dlSubdir": "0<[m",-                                        "dlTag": null,-                                        "dlUri": "http:mkicwhw"-                                    },-                                    "( > 3.1.3 && >= 4.5.1 )": {-                                        "dlCSize": 5,-                                        "dlHash": "eroc",-                                        "dlOutput": null,-                                        "dlSubdir": "\u0014󿯙{\u0003",-                                        "dlTag": [-                                            "old",-                                            "",-                                            "Prerelease",-                                            "LatestPrerelease",-                                            "Prerelease",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:clc"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -6,-                                        "dlHash": "t",-                                        "dlOutput": "}<dr𡵃[",-                                        "dlSubdir": {-                                            "RegexDir": "􈑙b􉰋"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:ggjmcsc"-                                    }-                                },-                                "Linux_Debian": {-                                    "( <= 4.2.2 && <= 3.4.2 )": {-                                        "dlCSize": 4,-                                        "dlHash": "sfd",-                                        "dlOutput": "\tGT5i",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Recommended",-                                            "\u0011􂵓*]",-                                            "Latest",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:uxtybkw"-                                    },-                                    "( <= 4.2.5 && > 5.3.3 && < 1.3.5 && == 2.2.1 )": {-                                        "dlCSize": 5,-                                        "dlHash": "mruvjkm",-                                        "dlOutput": "t󻸩\u00172AcM",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "Experimental",-                                            "Latest",-                                            "Experimental",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:v"-                                    },-                                    "( == 3.2.3 && >= 4.3.3 && == 5.2.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "jas",-                                        "dlOutput": "$𘔩RL",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -6,-                                        "dlHash": "bjxqp",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "􇴦Ky/"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:hico"-                                    }-                                },-                                "Linux_Fedora": {-                                    "( == 3.4.3 )": {-                                        "dlCSize": -1,-                                        "dlHash": "hucnxw",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "\n"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:zry"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -2,-                                        "dlHash": "wplay",-                                        "dlOutput": "\u0005􆄑GOJ驏",-                                        "dlSubdir": "{G",-                                        "dlTag": [-                                            "Latest",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:dv"-                                    }-                                },-                                "Linux_Gentoo": {-                                    "( <= 3.2.4 && >= 2.4.2 && < 5.3.1 && <= 2.3.1 && > 1.2.5 && == 4.2.2 ) || ( > 2.4.3 ) || ( > 1.2.3 )": {-                                        "dlCSize": -6,-                                        "dlHash": "dj",-                                        "dlOutput": "EhI􅐪􇔙%E",-                                        "dlSubdir": "\u000bHL􍥕\u0005u",-                                        "dlTag": [-                                            "LatestNightly",-                                            "LatestPrerelease",-                                            "base-1.3.6",-                                            "",-                                            "base-3.3.2",-                                            "LatestPrerelease",-                                            "base-4.1.4"-                                        ],-                                        "dlUri": "https:jhlim"-                                    },-                                    "( == 4.1.1 && <= 2.1.1 && >= 1.3.5 )": {-                                        "dlCSize": -7,-                                        "dlHash": "uupjxj",-                                        "dlOutput": null,-                                        "dlSubdir": "",-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    },-                                    "( > 1.4.1 ) || ( >= 4.3.4 && < 3.3.4 && > 2.3.4 && <= 3.3.1 ) || ( > 3.2.3 && <= 3.1.1 && > 2.3.2 ) || ( == 2.1.1 && >= 2.1.2 && == 2.2.2 )": {-                                        "dlCSize": 0,-                                        "dlHash": "gj",-                                        "dlOutput": "",-                                        "dlSubdir": "n",-                                        "dlTag": [-                                            "Prerelease",-                                            "old",-                                            "Nightly",-                                            "Latest",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:x"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 2,-                                        "dlHash": "wrtta",-                                        "dlOutput": "\u000e}<9\u0010f㴿",-                                        "dlSubdir": "􆅿󹧘ke",-                                        "dlTag": [-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:jspzzr"-                                    }-                                }-                            },-                            "A_Sparc64": {}-                        },-                        "viChangeLog": "https:waroy",-                        "viPostInstall": "drhyyr",-                        "viPostRemove": null,-                        "viPreCompile": null,-                        "viPreInstall": "psnezi",-                        "viReleaseDay": null,-                        "viSourceDL": {-                            "dlCSize": -1,-                            "dlHash": "e",-                            "dlOutput": "󶺙|",-                            "dlSubdir": null,-                            "dlTag": [-                                "Latest"-                            ],-                            "dlUri": "https:k"-                        },-                        "viTags": [-                            "Nightly"-                        ],-                        "viTestDL": null-                    },-                    "2.4.6": {-                        "viArch": {-                            "A_64": {-                                "Darwin": {-                                    "( < 2.1.6 && < 3.2.4 && > 4.5.2 && <= 5.1.3 && > 4.5.3 )": {-                                        "dlCSize": -4,-                                        "dlHash": "lpeacsa",-                                        "dlOutput": "fB\u000b𤧢s\u001d",-                                        "dlSubdir": {-                                            "RegexDir": "􂮓"-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:totyx"-                                    },-                                    "( < 3.2.5 && <= 3.1.3 ) || ( <= 1.1.3 && == 3.1.2 && >= 1.1.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": "\u001b􆋇j",-                                        "dlSubdir": "d􀇢\tM:",-                                        "dlTag": null,-                                        "dlUri": "http:axslbto"-                                    },-                                    "( <= 1.5.3 && > 3.3.5 && <= 5.3.5 && <= 1.3.3 && >= 3.5.3 && > 4.2.2 )": {-                                        "dlCSize": -7,-                                        "dlHash": "ulln",-                                        "dlOutput": "\t\u001d󿫎T",-                                        "dlSubdir": "",-                                        "dlTag": null,-                                        "dlUri": "https:vd"-                                    },-                                    "( > 4.1.1 && < 2.4.5 && > 4.3.3 && >= 1.1.3 ) || ( >= 3.4.4 ) || ( < 1.1.3 && >= 1.2.2 && <= 1.3.2 && > 3.3.3 ) || ( >= 1.1.2 && == 2.1.2 && == 2.1.2 ) || ( > 1.1.1 && >= 1.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "zcxpsnc",-                                        "dlOutput": "+\u001b",-                                        "dlSubdir": {-                                            "RegexDir": "53?􃹆_􆞳"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "Prerelease",-                                            "base-1.5.1",-                                            "jA",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:mnfj"-                                    },-                                    "( >= 3.1.5 && < 4.5.1 && < 1.1.4 && >= 1.6.2 && > 1.4.5 ) || ( <= 1.1.4 )": {-                                        "dlCSize": 3,-                                        "dlHash": "vnsndb",-                                        "dlOutput": ">#",-                                        "dlSubdir": "􇍅\u001ch\u0014",-                                        "dlTag": null,-                                        "dlUri": "http:zmmaovf"-                                    },-                                    "( >= 5.3.5 && < 4.1.3 && > 5.3.3 && > 1.2.4 && >= 2.1.2 && == 4.4.5 )": {-                                        "dlCSize": -3,-                                        "dlHash": "z",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "qI\"\u0019"-                                        },-                                        "dlTag": [-                                            ",^ᒐ𤳮\u001cn",-                                            "LatestPrerelease",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "nbdqdm",-                                        "dlOutput": ":u`u>g",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [],-                                        "dlUri": "http:n"-                                    }-                                },-                                "Linux_Debian": {},-                                "Windows": {-                                    "( <= 5.1.3 && >= 4.5.5 && < 5.2.4 && > 5.1.1 && > 4.2.3 && <= 1.2.3 && < 2.2.5 ) || ( >= 3.3.4 && <= 3.3.4 ) || ( > 1.2.3 && < 1.2.2 && >= 2.3.2 ) || ( < 2.3.2 && <= 2.3.1 ) || ( < 1.2.1 && <= 1.1.1 && >= 1.1.1 ) || ( > 2.1.1 && == 1.1.1 ) || ( == 1.1.1 ) || ( >= 2.1.1 )": {-                                        "dlCSize": 5,-                                        "dlHash": "eqka",-                                        "dlOutput": "]V",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:ebzhvus"-                                    },-                                    "( == 1.2.2 )": {-                                        "dlCSize": 3,-                                        "dlHash": "udxlgox",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "@😡IM"-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "𫝜n𢃑\u000e,䳞",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:psohtx"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -5,-                                        "dlHash": "uqb",-                                        "dlOutput": "+􊔛􋘓𤥙",-                                        "dlSubdir": {-                                            "RegexDir": "\u0004W\u0013􀐦"-                                        },-                                        "dlTag": [],-                                        "dlUri": "http:tpqz"-                                    }-                                }-                            },-                            "A_PowerPC": {-                                "Darwin": {-                                    "( < 2.1.3 && == 4.2.5 && < 5.6.5 )": {-                                        "dlCSize": 6,-                                        "dlHash": "bprb",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "𭸴𘗰"-                                        },-                                        "dlTag": [-                                            "base-5.6.1",-                                            "Nightly",-                                            "LatestPrerelease",-                                            "Nightly",-                                            "Recommended",-                                            "Prerelease",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( <= 2.3.2 ) || ( < 4.3.1 && == 4.4.3 && >= 4.2.1 && == 2.2.4 ) || ( == 3.3.3 ) || ( >= 1.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "icxyjcb",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "XrB\u0003>R"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:ee"-                                    },-                                    "( == 5.1.5 && < 4.1.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "wnw",-                                        "dlOutput": "3띩u\u0010\r",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    },-                                    "( == 6.3.5 && == 1.1.5 && == 2.1.3 && <= 2.3.5 && >= 5.3.2 && < 3.5.1 && == 1.5.3 )": {-                                        "dlCSize": -1,-                                        "dlHash": "oysxdu",-                                        "dlOutput": "] t8\u00036􆠎",-                                        "dlSubdir": "𩸓R^E",-                                        "dlTag": [-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:yk"-                                    },-                                    "( >= 3.2.3 && <= 2.2.5 && < 1.4.3 && <= 3.2.5 && > 1.3.2 && == 5.2.3 ) || ( < 1.4.1 && == 4.3.4 && == 1.1.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "slnqg",-                                        "dlOutput": "1h\"\u001clD7",-                                        "dlSubdir": {-                                            "RegexDir": "Ft󺆹4+"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:aud"-                                    }-                                },-                                "FreeBSD": {},-                                "Linux_Void": {},-                                "Windows": {-                                    "( < 1.4.4 && == 3.5.1 )": {-                                        "dlCSize": 6,-                                        "dlHash": "yrcimeg",-                                        "dlOutput": "",-                                        "dlSubdir": "𐧍𘓗􂓒𮧑",-                                        "dlTag": null,-                                        "dlUri": "https:teo"-                                    },-                                    "( < 5.1.1 && < 3.2.5 && <= 4.2.1 && <= 4.1.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "i",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:rujd"-                                    },-                                    "( == 1.5.1 && > 3.2.1 && >= 4.5.2 && == 3.4.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "ysm",-                                        "dlOutput": "^𨷴\u0016uk:",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:ggyfkie"-                                    },-                                    "( == 2.2.1 && >= 5.2.5 && <= 4.4.1 && >= 1.4.5 && <= 4.5.2 && <= 5.5.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "jrcnn",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "󷅋􉷼"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    },-                                    "( == 5.2.2 && == 4.3.2 && >= 2.4.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "o󰚜󹋀"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:w"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "westo",-                                        "dlOutput": "j5\"lS|󿿈",-                                        "dlSubdir": {-                                            "RegexDir": "覆"-                                        },-                                        "dlTag": [-                                            ".\u0011𡀭\u0018",-                                            "old",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:xmwvul"-                                    }-                                }-                            },-                            "A_Sparc64": {-                                "Darwin": {-                                    "( <= 3.3.5 && < 1.4.1 && >= 4.2.2 && > 2.5.4 && <= 6.2.1 ) || ( > 4.3.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "zzboa",-                                        "dlOutput": "􀚛",-                                        "dlSubdir": "\u001f",-                                        "dlTag": [-                                            "old",-                                            "Nightly",-                                            "Recommended",-                                            "LatestPrerelease",-                                            "Prerelease",-                                            "Recommended",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:tlnpgv"-                                    },-                                    "( >= 4.2.2 && == 5.5.4 ) || ( < 1.4.1 && == 4.4.2 && <= 2.1.1 && == 5.3.4 && < 1.3.4 )": {-                                        "dlCSize": -2,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-1.4.2",-                                            "Experimental",-                                            "Latest",-                                            "Recommended",-                                            "LatestPrerelease",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": "M",-                                        "dlTag": [-                                            "Latest",-                                            "LatestPrerelease",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:j"-                                    }-                                },-                                "FreeBSD": {-                                    "( == 2.5.3 && == 1.5.4 && >= 1.2.3 && < 1.1.5 ) || ( < 2.3.2 && <= 3.3.1 && >= 4.3.2 && <= 3.4.1 )": {-                                        "dlCSize": 0,-                                        "dlHash": "ind",-                                        "dlOutput": "@",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Recommended"-                                        ],-                                        "dlUri": "http:x"-                                    },-                                    "( >= 2.5.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "em",-                                        "dlOutput": "P",-                                        "dlSubdir": {-                                            "RegexDir": "𥻩\u0019l"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "LatestPrerelease",-                                            "LatestPrerelease",-                                            "Nightly",-                                            "old"-                                        ],-                                        "dlUri": "https:tzcy"-                                    },-                                    "( >= 3.5.1 && > 3.2.3 && <= 6.2.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": "|",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "https:q"-                                    },-                                    "( >= 5.5.5 && >= 3.3.4 ) || ( <= 1.4.4 && < 4.2.2 && <= 2.4.1 && <= 3.1.4 && >= 3.2.3 )": {-                                        "dlCSize": 0,-                                        "dlHash": "yr",-                                        "dlOutput": null,-                                        "dlSubdir": "n[1螛",-                                        "dlTag": null,-                                        "dlUri": "https:qbrzj"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 0,-                                        "dlHash": "iooqt",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Nightly",-                                            "LatestPrerelease",-                                            "Recommended",-                                            "Latest",-                                            "Prerelease",-                                            "base-6.5.6"-                                        ],-                                        "dlUri": "http:"-                                    }-                                },-                                "Windows": {-                                    "( >= 1.1.1 && >= 2.2.2 ) || ( > 4.2.2 && >= 4.2.2 && == 3.1.1 && == 2.1.3 && <= 4.4.5 && == 3.2.3 )": {-                                        "dlCSize": -4,-                                        "dlHash": "jpevks",-                                        "dlOutput": "wW3/h;ꋟ",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:fjni"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 0,-                                        "dlHash": "pb",-                                        "dlOutput": "]􄒧a!V\n\u0010",-                                        "dlSubdir": {-                                            "RegexDir": "\"iV5"-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:ppxe"-                                    }-                                }-                            }-                        },-                        "viChangeLog": "http:kezg",-                        "viPostInstall": "q",-                        "viPostRemove": "pq",-                        "viPreCompile": "rppwcvp",-                        "viPreInstall": "gpxfxy",-                        "viReleaseDay": "8645004479922981-03-17",-                        "viSourceDL": {-                            "dlCSize": -6,-                            "dlHash": "clndqp",-                            "dlOutput": "쒚\u000e|",-                            "dlSubdir": {-                                "RegexDir": "c𭣚\u001d"-                            },-                            "dlTag": [-                                "Recommended",-                                "Nightly",-                                "Experimental"-                            ],-                            "dlUri": "https:gx"-                        },-                        "viTags": [-                            "LatestPrerelease",-                            "Nightly",-                            "Nightly",-                            "Experimental"-                        ],-                        "viTestDL": {-                            "dlCSize": -1,-                            "dlHash": "osfn",-                            "dlOutput": "􉼑\u0014?]𰼲",-                            "dlSubdir": "𡤼\u000e]\\\u0014",-                            "dlTag": [-                                "Nightly",-                                "old",-                                "Prerelease",-                                "base-5.4.3",-                                "Latest"-                            ],-                            "dlUri": "http:ylgyiv"-                        }-                    },-                    "3.8.1": {-                        "viArch": {-                            "A_ARM": {-                                "Darwin": {-                                    "( <= 3.4.3 && == 4.3.2 && >= 5.3.5 && <= 1.4.2 && > 5.1.2 ) || ( <= 1.3.2 && < 2.4.4 && < 4.4.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "zj",-                                        "dlOutput": "\u0005􆽧󽹠dG",-                                        "dlSubdir": "",-                                        "dlTag": null,-                                        "dlUri": "https:"-                                    }-                                },-                                "FreeBSD": {-                                    "( < 1.5.3 && < 2.4.1 && > 5.1.5 )": {-                                        "dlCSize": -6,-                                        "dlHash": "ljovcfo",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Experimental",-                                            "LatestNightly",-                                            "浂9E",-                                            "",-                                            "old",-                                            "old",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:o"-                                    }-                                },-                                "Linux_Debian": {-                                    "( < 3.3.1 && <= 5.1.1 && < 5.3.1 && <= 5.2.2 && == 5.1.4 && >= 2.2.4 && < 5.4.5 ) || ( < 1.4.4 && >= 1.3.3 && <= 2.2.3 && <= 1.4.3 ) || ( >= 3.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "jylrmie",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:scp"-                                    },-                                    "( >= 3.2.4 && >= 4.3.3 && >= 3.5.3 && == 5.4.1 && > 3.4.5 && == 2.5.3 && > 5.2.4 ) || ( < 2.4.2 && <= 2.4.4 && >= 2.2.4 && < 2.4.3 ) || ( > 1.2.3 ) || ( == 2.1.2 && == 2.1.3 && == 1.2.1 ) || ( < 1.1.2 )": {-                                        "dlCSize": -5,-                                        "dlHash": "ruvn",-                                        "dlOutput": "",-                                        "dlSubdir": "7v",-                                        "dlTag": [-                                            "LatestNightly",-                                            "old",-                                            "old",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:jq"-                                    },-                                    "( >= 4.5.5 && < 1.5.4 && > 5.2.4 && < 1.1.2 && <= 1.2.4 && <= 2.4.4 && > 2.2.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "qpkwjlj",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "i\u0000"-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:zyqs"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 4,-                                        "dlHash": "gziqqyc",-                                        "dlOutput": null,-                                        "dlSubdir": "􃚱O)\u0015\u0005",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Prerelease",-                                            "Experimental",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:qeecime"-                                    }-                                },-                                "Windows": {-                                    "( < 1.2.5 )": {-                                        "dlCSize": 7,-                                        "dlHash": "nkhnay",-                                        "dlOutput": null,-                                        "dlSubdir": "T𣥺|~%e",-                                        "dlTag": [-                                            "Recommended",-                                            "LatestPrerelease",-                                            "Prerelease",-                                            "Experimental",-                                            "Experimental",-                                            "Experimental",-                                            "base-3.4.6"-                                        ],-                                        "dlUri": "https:dtrks"-                                    },-                                    "( < 2.5.2 && == 1.4.1 && > 5.3.4 && <= 5.3.5 && <= 1.3.1 && == 4.5.1 && >= 4.4.4 )": {-                                        "dlCSize": 3,-                                        "dlHash": "p",-                                        "dlOutput": "i馽",-                                        "dlSubdir": "`",-                                        "dlTag": [],-                                        "dlUri": "https:"-                                    },-                                    "( == 3.1.3 && < 1.3.2 )": {-                                        "dlCSize": 4,-                                        "dlHash": "urxrnw",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "𘝥\u000fpP"-                                        },-                                        "dlTag": [-                                            "base-6.5.4",-                                            "Nightly",-                                            "Latest"-                                        ],-                                        "dlUri": "https:sfq"-                                    },-                                    "( >= 2.2.2 )": {-                                        "dlCSize": -2,-                                        "dlHash": "p",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Cs􃋎𥷗S",-                                            "Nightly",-                                            "⏡\u0001\u001e\u0010",-                                            "Prerelease",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:xzprxly"-                                    },-                                    "( >= 5.2.4 && >= 1.4.2 && > 2.2.3 && >= 2.3.1 ) || ( <= 1.3.2 )": {-                                        "dlCSize": 2,-                                        "dlHash": "",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestNightly",-                                            "Latest",-                                            "LatestNightly",-                                            "Latest",-                                            "Prerelease",-                                            "m\\\u0011",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:ljc"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 2,-                                        "dlHash": "ykoghr",-                                        "dlOutput": "r",-                                        "dlSubdir": "\u0010`Z􏨎",-                                        "dlTag": [],-                                        "dlUri": "https:drhdzz"-                                    }-                                }-                            },-                            "A_Sparc": {-                                "Linux_Debian": {-                                    "( == 4.1.6 && <= 2.4.2 && < 3.3.5 && == 3.2.3 )": {-                                        "dlCSize": 4,-                                        "dlHash": "ir",-                                        "dlOutput": "=A",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease",-                                            "Nightly",-                                            "base-3.5.5"-                                        ],-                                        "dlUri": "https:w"-                                    },-                                    "( >= 4.4.4 && >= 3.1.3 && >= 5.1.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "g",-                                        "dlOutput": "\u0007\u001bH𑂝\u001d",-                                        "dlSubdir": {-                                            "RegexDir": "\u001a\u0016􈕒^"-                                        },-                                        "dlTag": [],-                                        "dlUri": "http:dnkh"-                                    }-                                },-                                "Linux_Ubuntu": {-                                    "( < 5.4.1 && > 3.6.4 && == 6.2.2 && <= 3.3.4 && <= 4.2.4 && > 1.1.4 )": {-                                        "dlCSize": -2,-                                        "dlHash": "hupr",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "old",-                                            "base-4.6.2",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "( < 5.4.4 && <= 2.5.1 && > 4.1.4 && <= 2.3.1 && >= 2.4.2 && < 4.5.5 )": {-                                        "dlCSize": -3,-                                        "dlHash": "vhjwyo",-                                        "dlOutput": "𢯆GM\u001ec玹s",-                                        "dlSubdir": "􃘚􉉧\u0005xꯟ",-                                        "dlTag": [-                                            "base-5.1.5",-                                            "old",-                                            "LatestNightly",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:jdzugm"-                                    },-                                    "( <= 3.3.4 && == 3.3.3 && == 1.3.1 && > 2.2.3 && == 3.1.2 && <= 2.3.4 && == 1.4.5 ) || ( < 4.2.1 && > 2.3.1 && < 1.3.3 && <= 3.1.4 && == 2.4.2 && == 4.1.3 ) || ( < 1.2.3 && >= 1.3.3 && > 3.2.1 && == 1.2.2 ) || ( < 2.1.1 && == 1.2.2 && < 2.1.2 && >= 2.1.1 ) || ( > 2.1.1 && <= 1.1.2 ) || ( <= 1.1.1 && >= 1.1.1 ) || ( == 1.1.1 )": {-                                        "dlCSize": -3,-                                        "dlHash": "",-                                        "dlOutput": "",-                                        "dlSubdir": ":",-                                        "dlTag": [-                                            "Recommended"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( >= 2.2.3 && >= 4.3.5 && < 4.2.1 && <= 4.4.1 && < 4.1.2 && <= 3.3.2 && <= 4.2.1 ) || ( < 4.2.3 )": {-                                        "dlCSize": -1,-                                        "dlHash": "sihxrs",-                                        "dlOutput": "\u000f󿖹𡙕",-                                        "dlSubdir": "\u001c\u0005\u0015",-                                        "dlTag": [-                                            "Experimental",-                                            "Experimental",-                                            "old",-                                            "base-1.2.6",-                                            "􏏮Ody"-                                        ],-                                        "dlUri": "https:bgnmbjh"-                                    },-                                    "( >= 3.2.3 && < 4.4.4 && < 4.2.2 && < 3.1.4 && < 4.3.1 && < 3.3.2 ) || ( < 2.3.4 && <= 4.4.3 && <= 4.1.1 && < 1.1.4 && >= 4.4.3 && <= 4.1.4 )": {-                                        "dlCSize": 6,-                                        "dlHash": "dnyw",-                                        "dlOutput": "d*󸄠\u0010",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:dzrpc"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 4,-                                        "dlHash": "",-                                        "dlOutput": "􁍚",-                                        "dlSubdir": {-                                            "RegexDir": "['\u0014/P\u000c"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Prerelease",-                                            "Latest",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:f"-                                    }-                                }-                            },-                            "A_Sparc64": {-                                "Darwin": {-                                    "( < 3.1.5 && <= 4.2.1 && <= 3.1.4 && < 4.4.3 ) || ( >= 4.1.2 && <= 1.1.4 )": {-                                        "dlCSize": 6,-                                        "dlHash": "bgw",-                                        "dlOutput": "M𰎔rk",-                                        "dlSubdir": {-                                            "RegexDir": "z\u0001"-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:"-                                    },-                                    "( < 4.2.2 && <= 3.3.3 && <= 3.1.4 && > 2.4.1 && < 1.4.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "clel",-                                        "dlOutput": "\u0014m󳏊7\u0014(",-                                        "dlSubdir": {-                                            "RegexDir": "珤g􎴞"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:lmb"-                                    },-                                    "( < 4.4.4 && > 4.2.3 && >= 5.1.3 && > 4.1.4 && > 1.1.1 && > 3.2.5 ) || ( > 1.4.4 && <= 4.4.5 && < 2.4.2 && == 2.2.3 )": {-                                        "dlCSize": -5,-                                        "dlHash": "",-                                        "dlOutput": "a5𩩎VE_D",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:"-                                    },-                                    "( == 4.3.3 && <= 4.5.3 && == 3.5.5 && > 2.2.4 && > 5.5.2 && > 1.6.6 && > 1.3.1 )": {-                                        "dlCSize": 3,-                                        "dlHash": "mradhp",-                                        "dlOutput": "\u0014𡱷\t`p:",-                                        "dlSubdir": "=󹹪",-                                        "dlTag": [],-                                        "dlUri": "https:htvzh"-                                    },-                                    "( == 5.4.4 && < 5.3.5 && < 4.4.4 && == 1.6.2 && < 1.5.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "ibgu",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Latest",-                                            "LatestPrerelease",-                                            "old"-                                        ],-                                        "dlUri": "https:vqweox"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 3,-                                        "dlHash": "suw",-                                        "dlOutput": "m\u001bT",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Nightly",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:pu"-                                    }-                                },-                                "FreeBSD": {-                                    "( <= 1.1.4 && >= 4.5.2 && == 3.4.4 && <= 1.3.1 && > 4.1.3 && >= 1.4.2 && > 2.2.4 ) || ( < 1.3.4 && < 2.4.2 && <= 3.1.2 && < 2.2.2 && == 4.1.4 && < 1.3.2 ) || ( >= 1.1.1 && == 3.3.1 && == 1.2.2 && == 3.2.4 ) || ( < 2.1.1 && >= 2.2.1 )": {-                                        "dlCSize": 0,-                                        "dlHash": "q",-                                        "dlOutput": "~󰖥\u0007/\u000c⒏g",-                                        "dlSubdir": {-                                            "RegexDir": "q'"-                                        },-                                        "dlTag": [-                                            "Latest",-                                            "Latest",-                                            "\u0011<",-                                            "old",-                                            "base-4.1.3"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "( <= 1.5.2 && > 3.5.1 ) || ( < 4.4.1 ) || ( < 2.2.2 && == 3.2.2 && < 3.1.3 && == 1.2.3 && < 2.1.3 ) || ( >= 1.1.1 && == 1.1.2 ) || ( < 2.1.1 ) || ( == 1.1.1 && > 1.1.1 )": {-                                        "dlCSize": 6,-                                        "dlHash": "v",-                                        "dlOutput": null,-                                        "dlSubdir": "zy󳛷)]㲍",-                                        "dlTag": [-                                            "Latest",-                                            "old",-                                            "old",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:n"-                                    },-                                    "( == 5.5.5 && < 2.1.2 && <= 1.1.5 && > 3.1.2 && <= 1.4.3 && < 5.4.2 )": {-                                        "dlCSize": -3,-                                        "dlHash": "daowsmd",-                                        "dlOutput": "𡕆",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    },-                                    "( >= 1.2.2 && < 2.3.3 && > 3.4.5 && == 5.4.5 && <= 4.2.5 && <= 3.5.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "i"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:kcf"-                                    },-                                    "( >= 3.4.4 ) || ( > 2.1.2 && >= 1.2.2 && >= 1.4.1 && > 3.4.5 && < 2.4.4 && >= 4.2.2 ) || ( == 2.3.3 && == 3.1.1 )": {-                                        "dlCSize": 5,-                                        "dlHash": "hbd",-                                        "dlOutput": "3􌠹X󻃃",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "Experimental",-                                            "old",-                                            "LatestNightly",-                                            "Prerelease",-                                            "LatestPrerelease",-                                            "\u0017)\u000c_l󴉀",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:esf"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -2,-                                        "dlHash": "ty",-                                        "dlOutput": "\u001b󸑇󽳮󻚷",-                                        "dlSubdir": {-                                            "RegexDir": "Iv㮜$\u0004"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "Prerelease",-                                            "Recommended",-                                            "Latest",-                                            "貄.F"-                                        ],-                                        "dlUri": "http:z"-                                    }-                                },-                                "Linux_RedHat": {-                                    "( <= 1.5.2 && > 4.5.3 && >= 3.1.5 && <= 4.4.2 && < 1.1.2 && < 4.2.4 ) || ( < 2.4.1 && <= 2.1.1 && >= 4.1.2 && >= 3.3.1 && > 2.4.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "fl",-                                        "dlOutput": null,-                                        "dlSubdir": "j􈿙`\u0014",-                                        "dlTag": [],-                                        "dlUri": "https:nqd"-                                    },-                                    "( == 5.2.2 && == 4.5.5 && == 3.5.1 && < 1.1.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": "ng",-                                        "dlSubdir": {-                                            "RegexDir": "⮾𠹂?􃬩"-                                        },-                                        "dlTag": [-                                            "K9O",-                                            "Latest",-                                            "LatestPrerelease",-                                            "Recommended",-                                            "Experimental",-                                            "LatestNightly",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:vmlr"-                                    },-                                    "( >= 3.1.4 ) || ( < 4.3.3 && < 3.2.4 && == 3.4.2 && > 3.4.4 ) || ( <= 3.2.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "pvqsdaa",-                                        "dlOutput": "􇈮",-                                        "dlSubdir": "\u0007钺\u001f𬝱",-                                        "dlTag": [],-                                        "dlUri": "http:z"-                                    },-                                    "( >= 3.4.5 && > 5.3.3 && < 1.4.1 && == 2.1.4 && == 4.4.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "zsn",-                                        "dlOutput": "\u0016󰺟3\"BO",-                                        "dlSubdir": "\u000e𣔿p_A",-                                        "dlTag": [-                                            "󸵠􃑉\u00177"-                                        ],-                                        "dlUri": "https:lpr"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -1,-                                        "dlHash": "w",-                                        "dlOutput": null,-                                        "dlSubdir": "\u001b􏜡\u0011",-                                        "dlTag": [-                                            "base-5.4.4",-                                            "Prerelease",-                                            "Nightly",-                                            "old",-                                            "Latest"-                                        ],-                                        "dlUri": "http:wgcsttg"-                                    }-                                },-                                "Linux_Ubuntu": {-                                    "( < 2.5.1 && <= 3.1.2 && >= 4.3.4 && < 4.1.3 && < 2.2.3 ) || ( <= 1.4.3 && == 2.3.2 ) || ( < 4.1.3 && == 2.1.3 )": {-                                        "dlCSize": -5,-                                        "dlHash": "c",-                                        "dlOutput": "𥶼瀻j\u0012𝓳/",-                                        "dlSubdir": {-                                            "RegexDir": "i"-                                        },-                                        "dlTag": [-                                            "⼱5\u0011􋍴",-                                            "Recommended",-                                            "base-3.4.3"-                                        ],-                                        "dlUri": "https:baieh"-                                    },-                                    "( > 3.4.5 ) || ( <= 2.4.4 && > 1.4.4 && <= 2.4.1 && <= 2.2.6 )": {-                                        "dlCSize": 2,-                                        "dlHash": "rksmvfr",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "base-5.1.3",-                                            "old",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:s"-                                    },-                                    "( >= 1.1.2 && == 3.1.5 && <= 5.1.1 && < 5.3.4 ) || ( == 1.1.4 && <= 3.2.1 && < 3.3.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "t",-                                        "dlOutput": "\u000bO􁁝𪎠o",-                                        "dlSubdir": "-j󳒃m",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "\u0000",-                                            "base-1.4.5",-                                            "Experimental",-                                            "Experimental",-                                            "Recommended",-                                            "old"-                                        ],-                                        "dlUri": "https:fyqen"-                                    }-                                },-                                "Windows": {-                                    "( >= 1.5.1 ) || ( <= 4.1.2 && < 2.3.2 && <= 2.2.2 )": {-                                        "dlCSize": 3,-                                        "dlHash": "zga",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "s\u0011\u0012󸶡2"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "0#",-                                            "LatestNightly",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( >= 5.4.1 && > 4.4.2 && > 4.2.2 && < 5.4.5 && < 3.2.3 && < 3.2.1 && > 2.4.3 ) || ( <= 2.3.1 && > 4.2.1 && < 2.1.2 ) || ( < 3.3.2 && > 3.3.3 && > 2.1.2 ) || ( <= 2.2.2 && == 1.2.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "ewrhaq",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "http:qqgl"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "fmblmdj",-                                        "dlOutput": "9",-                                        "dlSubdir": {-                                            "RegexDir": " 怶\u000f𫓝F"-                                        },-                                        "dlTag": [-                                            "󲑇q\u0015",-                                            "old",-                                            "LatestNightly",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:ptpzv"-                                    }-                                }-                            }-                        },-                        "viChangeLog": "http:vaa",-                        "viPostInstall": null,-                        "viPostRemove": null,-                        "viPreCompile": null,-                        "viPreInstall": "buwpwbj",-                        "viReleaseDay": "-18833626801749283-08-10",-                        "viSourceDL": null,-                        "viTags": [],-                        "viTestDL": null-                    },-                    "4.6.7": {-                        "viArch": {-                            "A_64": {-                                "FreeBSD": {}-                            },-                            "A_Sparc64": {-                                "Windows": {-                                    "( < 1.5.5 )": {-                                        "dlCSize": -4,-                                        "dlHash": "",-                                        "dlOutput": "q𪟻)",-                                        "dlSubdir": {-                                            "RegexDir": "󽁦\u0011y𬕫"-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "Latest",-                                            "Prerelease",-                                            "old",-                                            "LatestNightly",-                                            "Recommended",-                                            "Latest"-                                        ],-                                        "dlUri": "https:mxtrdx"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -6,-                                        "dlHash": "sy",-                                        "dlOutput": "\u000c+[",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Latest",-                                            "Experimental",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:hgmevc"-                                    }-                                }-                            }-                        },-                        "viChangeLog": "http:wqs",-                        "viPostInstall": "",-                        "viPostRemove": null,-                        "viPreCompile": null,-                        "viPreInstall": null,-                        "viReleaseDay": "12686742183186342-03-13",-                        "viSourceDL": {-                            "dlCSize": 4,-                            "dlHash": "tisnp",-                            "dlOutput": "~\u0013󾅬𛉂𱷉􅊸",-                            "dlSubdir": null,-                            "dlTag": null,-                            "dlUri": "http:c"-                        },-                        "viTags": [-                            "LatestPrerelease",-                            "\u0000\u000f",-                            "W",-                            "Latest"-                        ],-                        "viTestDL": null-                    },-                    "4.7.5": {-                        "viArch": {},-                        "viChangeLog": "https:gkfn",-                        "viPostInstall": "trfpyky",-                        "viPostRemove": "cd",-                        "viPreCompile": null,-                        "viPreInstall": null,-                        "viReleaseDay": "23792748981354003-09-27",-                        "viSourceDL": {-                            "dlCSize": 1,-                            "dlHash": "myfcnq",-                            "dlOutput": "𨖷\u0000HY,",-                            "dlSubdir": null,-                            "dlTag": [-                                "base-5.5.2",-                                "Nightly",-                                "Prerelease",-                                "LatestPrerelease",-                                "old",-                                "Y彪b"-                            ],-                            "dlUri": "https:"-                        },-                        "viTags": [-                            "Nightly",-                            "old",-                            "Recommended",-                            "LatestNightly"-                        ],-                        "viTestDL": {-                            "dlCSize": 6,-                            "dlHash": "i",-                            "dlOutput": "𰟟",-                            "dlSubdir": "Bl",-                            "dlTag": [-                                "Experimental"-                            ],-                            "dlUri": "http:odr"-                        }-                    },-                    "5.4.7": {-                        "viArch": {-                            "A_PowerPC": {}-                        },-                        "viChangeLog": "http:axls",-                        "viPostInstall": "phmfx",-                        "viPostRemove": "xb",-                        "viPreCompile": "iyzbsvj",-                        "viPreInstall": "yanfjz",-                        "viReleaseDay": "2519010635288629-07-07",-                        "viSourceDL": {-                            "dlCSize": null,-                            "dlHash": "zglr",-                            "dlOutput": "𩏱2𪎍",-                            "dlSubdir": "I0Tu",-                            "dlTag": null,-                            "dlUri": "http:gc"-                        },-                        "viTags": [-                            "Recommended",-                            "Nightly",-                            "Prerelease",-                            "old"-                        ],-                        "viTestDL": null-                    },-                    "8.8.5": {-                        "viArch": {-                            "A_32": {-                                "Darwin": {-                                    "( < 6.3.1 && == 3.5.5 && <= 5.4.1 && == 2.5.1 && <= 2.2.1 && >= 2.4.4 )": {-                                        "dlCSize": 2,-                                        "dlHash": "vm",-                                        "dlOutput": "𫪥⓰Ip=􍕪",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "Latest",-                                            "C"-                                        ],-                                        "dlUri": "https:swco"-                                    },-                                    "( == 2.1.5 && >= 1.3.6 && < 3.1.5 && == 3.3.2 && < 1.3.4 && == 2.5.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "mrkbneu",-                                        "dlOutput": "B󸢃",-                                        "dlSubdir": {-                                            "RegexDir": "X􈷰"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:r"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 0,-                                        "dlHash": "eyjyim",-                                        "dlOutput": "0􄽝",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:uz"-                                    }-                                },-                                "Linux_Exherbo": {-                                    "( < 2.2.1 && <= 2.2.5 && < 2.3.5 && == 3.5.2 && == 5.3.5 && < 1.2.2 )": {-                                        "dlCSize": 1,-                                        "dlHash": "n",-                                        "dlOutput": "v/\u0005l􈙓",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-4.1.5",-                                            "Latest"-                                        ],-                                        "dlUri": "https:j"-                                    },-                                    "( < 3.2.5 && < 2.2.3 )": {-                                        "dlCSize": 2,-                                        "dlHash": "tcuwfa",-                                        "dlOutput": "L-𥈍F",-                                        "dlSubdir": {-                                            "RegexDir": "􀫬^"-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "base-2.4.6"-                                        ],-                                        "dlUri": "https:z"-                                    },-                                    "( <= 2.3.4 && >= 1.4.2 && > 5.2.2 )": {-                                        "dlCSize": 6,-                                        "dlHash": "znaopyf",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "\u000c􎘑"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "Prerelease",-                                            "base-5.1.2",-                                            "Experimental",-                                            "Latest",-                                            ""-                                        ],-                                        "dlUri": "http:plyzn"-                                    },-                                    "( == 3.1.1 && < 2.4.1 && < 5.4.5 && == 3.2.3 && == 5.3.1 && < 4.2.3 && > 1.5.3 ) || ( == 3.1.3 && >= 4.2.4 && < 4.4.3 && >= 1.2.2 && < 3.1.4 && == 2.3.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "juture",-                                        "dlOutput": "<",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:eppi"-                                    },-                                    "( > 1.2.3 && >= 1.6.4 ) || ( >= 2.2.3 && > 3.1.3 ) || ( >= 3.2.1 ) || ( <= 2.1.3 ) || ( == 1.1.1 && > 1.1.1 && <= 1.1.1 ) || ( >= 2.1.1 && > 1.1.1 )": {-                                        "dlCSize": -1,-                                        "dlHash": "laa",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "\u0000A􂼖"-                                        },-                                        "dlTag": [-                                            "base-6.6.1",-                                            "N5'𰾦𡣪f",-                                            "base-3.5.2",-                                            "Latest",-                                            "Recommended",-                                            "Recommended",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "( > 6.2.5 ) || ( >= 5.1.1 )": {-                                        "dlCSize": 3,-                                        "dlHash": "peo",-                                        "dlOutput": "s\u001c@{\u0019",-                                        "dlSubdir": {-                                            "RegexDir": "<喓𢷻\u0017\t"-                                        },-                                        "dlTag": [-                                            "Recommended",-                                            "base-1.1.1",-                                            "old",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:eyki"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -6,-                                        "dlHash": "qhgti",-                                        "dlOutput": "*^XU9",-                                        "dlSubdir": "&\n",-                                        "dlTag": [-                                            "D\u0016\u0012W.",-                                            "LatestPrerelease",-                                            "LatestNightly",-                                            "old",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:eszn"-                                    }-                                },-                                "Linux_Fedora": {-                                    "( == 1.2.5 && >= 4.1.1 && > 3.2.1 && >= 4.2.5 && == 3.2.4 && == 4.4.2 && == 5.1.1 ) || ( < 2.2.3 )": {-                                        "dlCSize": 7,-                                        "dlHash": "hvuf",-                                        "dlOutput": "S[::\u0005",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "LatestNightly",-                                            "base-2.4.1",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( == 4.2.3 && > 5.1.2 ) || ( > 1.3.2 ) || ( < 1.2.1 && == 2.2.2 && < 2.1.2 && == 2.1.2 && > 2.2.3 ) || ( < 1.1.2 && == 2.2.2 ) || ( > 1.1.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "qcd",-                                        "dlOutput": "K@",-                                        "dlSubdir": "x󿁕L",-                                        "dlTag": [-                                            "Prerelease",-                                            ""-                                        ],-                                        "dlUri": "http:oqfl"-                                    },-                                    "( > 5.2.1 && <= 1.3.4 && <= 5.5.3 && >= 1.5.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "gzyhvwf",-                                        "dlOutput": "\u0011􍍍",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:ze"-                                    },-                                    "( > 5.4.1 )": {-                                        "dlCSize": 0,-                                        "dlHash": "kpl",-                                        "dlOutput": "\u0011:Ok",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Nightly",-                                            "Experimental",-                                            "Nightly",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:cavdxd"-                                    },-                                    "( >= 3.5.5 && < 3.5.1 && <= 3.4.3 && == 2.1.4 && > 1.6.1 && <= 4.3.2 ) || ( >= 3.4.2 && > 4.1.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": ",\u0019𡐭6R\t",-                                        "dlSubdir": "1OP",-                                        "dlTag": [-                                            "Recommended",-                                            "Nightly",-                                            "base-2.3.1",-                                            "Experimental",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:n"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -7,-                                        "dlHash": "ti",-                                        "dlOutput": "􊗰wIfe",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:a"-                                    }-                                }-                            },-                            "A_PowerPC": {-                                "Linux_Fedora": {-                                    "( <= 1.2.2 ) || ( < 4.1.3 )": {-                                        "dlCSize": 4,-                                        "dlHash": "ov",-                                        "dlOutput": "x\u000b􊙂i",-                                        "dlSubdir": {-                                            "RegexDir": "󿆋㈽簾\u000b"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:xkdhe"-                                    },-                                    "( <= 3.2.5 && < 3.3.2 && == 3.2.5 && <= 1.2.4 && >= 5.5.4 && < 5.2.2 && > 3.2.1 ) || ( >= 4.4.2 && <= 1.4.3 && >= 2.4.2 && >= 2.3.4 && >= 4.4.2 && == 4.4.2 ) || ( == 1.1.3 && > 2.1.2 && <= 2.2.2 && <= 2.3.2 )": {-                                        "dlCSize": -6,-                                        "dlHash": "gy",-                                        "dlOutput": "r\u000c8ᆝ&\u0016",-                                        "dlSubdir": {-                                            "RegexDir": "!"-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "LatestPrerelease",-                                            "old",-                                            "old"-                                        ],-                                        "dlUri": "http:gcnk"-                                    },-                                    "( > 4.4.4 && <= 3.1.5 ) || ( == 4.3.2 && == 3.2.1 && <= 2.1.1 && >= 2.2.2 && > 3.4.4 && < 4.1.1 ) || ( > 2.3.2 && <= 2.3.2 && >= 1.1.1 && < 3.3.2 && <= 1.3.1 )": {-                                        "dlCSize": 2,-                                        "dlHash": "jfsqbw",-                                        "dlOutput": "3p",-                                        "dlSubdir": {-                                            "RegexDir": "􈋷.\n"-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "LatestNightly",-                                            "base-6.3.6",-                                            "Nightly",-                                            "Nightly",-                                            "Recommended",-                                            "Latest"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "( >= 4.4.3 && >= 1.2.4 && <= 4.2.2 && < 2.6.3 && == 5.5.5 && > 2.2.1 && <= 1.1.4 ) || ( <= 4.1.2 && <= 3.4.4 ) || ( < 3.1.3 )": {-                                        "dlCSize": 5,-                                        "dlHash": "puhuxc",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "7"-                                        },-                                        "dlTag": [-                                            "old"-                                        ],-                                        "dlUri": "https:jugqioa"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 4,-                                        "dlHash": "",-                                        "dlOutput": "t\niZDlB",-                                        "dlSubdir": "ZGC􄸌󶰄",-                                        "dlTag": [-                                            "base-5.6.1",-                                            "base-6.1.1",-                                            "Prerelease",-                                            "\u000b'",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:cg"-                                    }-                                },-                                "Linux_Gentoo": {},-                                "Windows": {}-                            },-                            "A_PowerPC64": {-                                "Darwin": {-                                    "( < 1.4.5 && > 1.5.2 && < 2.1.1 && > 4.3.5 && == 6.1.2 )": {-                                        "dlCSize": -3,-                                        "dlHash": "ladxcc",-                                        "dlOutput": "9􌔔㽪",-                                        "dlSubdir": "",-                                        "dlTag": [],-                                        "dlUri": "https:zzyxu"-                                    },-                                    "( < 2.3.2 ) || ( < 3.3.1 && == 2.3.1 && > 1.2.1 ) || ( >= 1.3.1 && > 3.3.3 && == 1.1.4 && == 2.2.1 && >= 4.3.3 )": {-                                        "dlCSize": -7,-                                        "dlHash": "xaswycm",-                                        "dlOutput": "'FV\u0012\r\u0007\u0011",-                                        "dlSubdir": {-                                            "RegexDir": "\u0011i󽖼RyS"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:btcz"-                                    },-                                    "( < 5.5.3 ) || ( > 3.1.3 && < 2.3.2 && == 5.1.4 && > 1.2.1 && < 1.1.3 )": {-                                        "dlCSize": -2,-                                        "dlHash": "z",-                                        "dlOutput": "!H/𐧝\u0002^",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "old",-                                            "Recommended",-                                            "Nightly",-                                            "Nightly",-                                            "Recommended",-                                            "S\r?􎿤V􀠾",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:egkuhbu"-                                    },-                                    "( <= 4.3.3 && == 3.2.4 && > 3.3.2 ) || ( >= 3.1.1 )": {-                                        "dlCSize": 4,-                                        "dlHash": "eq",-                                        "dlOutput": "亅救",-                                        "dlSubdir": {-                                            "RegexDir": "d\u0019"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:uu"-                                    },-                                    "( <= 5.5.4 && == 5.2.3 && <= 2.4.6 && <= 2.4.5 && >= 1.4.3 && <= 4.2.2 ) || ( <= 3.1.2 )": {-                                        "dlCSize": -4,-                                        "dlHash": "xspjlhf",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Nightly",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:acailu"-                                    },-                                    "( > 4.5.1 ) || ( < 4.3.4 ) || ( > 1.2.2 && < 2.1.1 && == 3.2.2 && <= 1.3.3 ) || ( > 1.2.1 && >= 2.2.1 && > 3.2.2 && == 2.1.1 ) || ( > 2.2.1 )": {-                                        "dlCSize": -6,-                                        "dlHash": "lgfjce",-                                        "dlOutput": "\u0013𰓘",-                                        "dlSubdir": {-                                            "RegexDir": "?"-                                        },-                                        "dlTag": [-                                            "Latest",-                                            "old",-                                            "base-5.3.6",-                                            "Latest",-                                            "LatestNightly",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:j"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 2,-                                        "dlHash": "hboqbmq",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ".LOp&="-                                        },-                                        "dlTag": [-                                            "Latest",-                                            "Recommended",-                                            "LatestPrerelease",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:jqe"-                                    }-                                },-                                "FreeBSD": {-                                    "( < 3.1.5 && < 1.1.1 && > 5.2.5 && < 3.2.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "dzcx",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ":\u001d)\u0005"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:suorba"-                                    },-                                    "( <= 2.1.2 && == 5.1.2 && >= 2.1.2 && == 1.3.6 && < 1.5.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "uldol",-                                        "dlOutput": "",-                                        "dlSubdir": "\u0003",-                                        "dlTag": [-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:ajbi"-                                    },-                                    "( <= 4.2.1 && > 2.1.3 && <= 4.2.1 )": {-                                        "dlCSize": 7,-                                        "dlHash": "b",-                                        "dlOutput": "F臫k󿁹",-                                        "dlSubdir": "&8\u0010a\u0004",-                                        "dlTag": null,-                                        "dlUri": "http:hqcm"-                                    },-                                    "( >= 4.3.3 && <= 1.3.3 && == 1.4.3 && < 2.2.2 && < 3.5.4 && > 5.4.2 && <= 3.1.1 ) || ( < 1.2.3 && == 1.3.1 && > 3.2.4 ) || ( >= 1.1.1 && >= 3.1.4 && > 1.2.2 && == 4.2.4 && == 2.3.2 ) || ( <= 1.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "W"-                                        },-                                        "dlTag": [-                                            "🙓\u0006+"-                                        ],-                                        "dlUri": "https:ffnh"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 4,-                                        "dlHash": "er",-                                        "dlOutput": "\u0012\u0004i띮",-                                        "dlSubdir": "e􍮮",-                                        "dlTag": [-                                            "Nightly",-                                            "base-4.2.6",-                                            "Experimental",-                                            "Latest"-                                        ],-                                        "dlUri": "https:aqsav"-                                    }-                                },-                                "Linux_Rocky": {-                                    "( < 1.4.5 && < 3.3.4 && >= 1.2.4 && <= 1.3.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "p",-                                        "dlOutput": "\u0018󾹉u󿑙Q",-                                        "dlSubdir": "𝃀0\u0004\u0014g",-                                        "dlTag": [],-                                        "dlUri": "http:"-                                    },-                                    "( < 4.1.5 && == 2.2.4 && <= 5.2.3 && <= 1.3.2 && < 5.5.2 && > 5.3.4 && <= 4.1.3 ) || ( <= 4.1.1 ) || ( > 2.3.1 && == 2.3.3 ) || ( == 2.3.2 && < 1.2.2 && < 1.2.2 ) || ( >= 2.1.1 && > 1.1.1 )": {-                                        "dlCSize": -1,-                                        "dlHash": "mdb",-                                        "dlOutput": "y9\u0003\u0002\u0006چN",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:rut"-                                    },-                                    "( <= 1.4.4 && > 5.3.3 ) || ( >= 4.2.4 && == 3.2.4 && <= 1.2.4 && > 1.2.2 && <= 4.2.3 && < 2.4.1 ) || ( <= 1.4.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "vz",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "Fz \u001bI^"-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "Prerelease",-                                            "base-1.4.1"-                                        ],-                                        "dlUri": "http:klwri"-                                    },-                                    "( <= 2.6.1 && >= 4.4.5 && == 5.4.1 && >= 3.3.4 ) || ( == 3.2.3 && >= 2.2.3 && > 1.3.3 && > 3.1.2 && < 4.4.3 ) || ( <= 2.2.2 )": {-                                        "dlCSize": -5,-                                        "dlHash": "dkezcms",-                                        "dlOutput": "g\u001d.0/_",-                                        "dlSubdir": "𖽼\u000e􌠠\\j",-                                        "dlTag": [-                                            "base-3.5.5",-                                            "LatestNightly",-                                            "LatestPrerelease",-                                            "Nightly",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:bi"-                                    },-                                    "( <= 4.2.3 ) || ( >= 1.3.1 && <= 2.1.4 ) || ( < 3.2.1 && < 3.3.1 ) || ( >= 1.1.2 && == 1.2.2 && > 1.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "htvgyzp",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:lohmaxy"-                                    },-                                    "( == 5.1.5 && < 1.1.2 && == 1.3.4 ) || ( > 2.2.2 && >= 1.3.2 && < 3.2.3 && == 2.2.2 && >= 1.2.1 ) || ( >= 2.1.2 && > 4.3.1 ) || ( > 2.1.1 )": {-                                        "dlCSize": -1,-                                        "dlHash": "rbj",-                                        "dlOutput": "쫤HO6",-                                        "dlSubdir": {-                                            "RegexDir": "J5"-                                        },-                                        "dlTag": [-                                            "Recommended",-                                            "base-6.6.3",-                                            "Latest",-                                            "Recommended",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:pit"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 7,-                                        "dlHash": "",-                                        "dlOutput": "[Q]𤝊\n󼥣",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Nightly",-                                            "Latest",-                                            "base-6.6.1",-                                            "LatestPrerelease",-                                            "Latest",-                                            "Latest",-                                            ""-                                        ],-                                        "dlUri": "https:zc"-                                    }-                                },-                                "Windows": {-                                    "( < 1.2.2 && <= 2.4.1 && > 5.3.5 && < 3.5.4 && == 2.5.4 )": {-                                        "dlCSize": 3,-                                        "dlHash": "jtzji",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "|E\u0012܍"-                                        },-                                        "dlTag": [-                                            "Experimental"-                                        ],-                                        "dlUri": "https:jpeifyl"-                                    },-                                    "( < 3.4.4 && < 3.2.5 && <= 1.4.1 && <= 5.2.6 && > 2.3.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "cprqudk",-                                        "dlOutput": "3蜜\u0018󽲹󹙿y]",-                                        "dlSubdir": {-                                            "RegexDir": "s\r\u001f^"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "( <= 4.5.5 && <= 4.4.1 && > 3.3.1 && == 4.1.5 )": {-                                        "dlCSize": -5,-                                        "dlHash": "ul",-                                        "dlOutput": "􈔞zb𗤴",-                                        "dlSubdir": "%:䌈",-                                        "dlTag": [-                                            "LatestNightly",-                                            "",-                                            "LatestNightly",-                                            "Recommended",-                                            "old",-                                            "base-2.4.3",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:mhl"-                                    },-                                    "( >= 2.4.3 && < 2.1.2 && == 1.5.4 && >= 5.2.5 ) || ( == 1.3.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "gfi",-                                        "dlOutput": "䥴\u00192\u000c􇷰D",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "http:zgt"-                                    }-                                }-                            },-                            "A_Sparc": {-                                "Darwin": {-                                    "( < 1.3.2 && > 2.4.4 && >= 5.5.1 )": {-                                        "dlCSize": 3,-                                        "dlHash": "zsivo",-                                        "dlOutput": "g[",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestNightly",-                                            "Recommended",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:lyrjv"-                                    },-                                    "( < 2.2.1 ) || ( <= 4.1.2 && >= 1.2.3 && <= 3.4.1 && < 3.1.4 && > 3.2.4 && >= 2.3.2 )": {-                                        "dlCSize": 0,-                                        "dlHash": "u",-                                        "dlOutput": "YD=󷭦",-                                        "dlSubdir": {-                                            "RegexDir": "󰋩\u0011𡹏󲏱%"-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:k"-                                    },-                                    "( < 4.3.2 && == 5.5.4 && == 3.5.4 && < 2.1.2 && == 1.2.3 ) || ( < 4.1.1 && >= 4.4.4 && < 1.1.3 && > 2.2.2 && > 1.3.2 && > 1.3.3 ) || ( == 1.3.2 && < 3.1.3 && > 1.1.1 ) || ( < 2.1.2 )": {-                                        "dlCSize": 7,-                                        "dlHash": "g",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "z𱲰󼴦"-                                        },-                                        "dlTag": [-                                            "",-                                            "Nightly",-                                            "Recommended",-                                            "Prerelease",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:vmxsaan"-                                    },-                                    "( <= 1.2.1 )": {-                                        "dlCSize": 2,-                                        "dlHash": "j",-                                        "dlOutput": "1",-                                        "dlSubdir": {-                                            "RegexDir": "\u0018)"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:lptwfeb"-                                    },-                                    "( <= 4.1.3 && == 4.4.5 && <= 3.5.1 && <= 5.3.2 && <= 3.3.2 && >= 5.5.5 && >= 3.3.1 )": {-                                        "dlCSize": -3,-                                        "dlHash": "yzrsgx",-                                        "dlOutput": "\u0018쨃",-                                        "dlSubdir": {-                                            "RegexDir": "*"-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "LatestNightly",-                                            "\u0012\u001a",-                                            "old",-                                            "base-5.3.5"-                                        ],-                                        "dlUri": "http:bilaipn"-                                    },-                                    "( >= 3.4.2 && <= 3.4.2 && <= 4.4.4 && > 1.1.4 && >= 3.1.4 && > 2.1.1 && > 3.2.4 ) || ( >= 1.1.4 && < 2.2.4 ) || ( <= 2.1.1 && > 2.2.1 && >= 1.3.1 && < 2.3.1 )": {-                                        "dlCSize": -2,-                                        "dlHash": "yjpv",-                                        "dlOutput": "􁔤",-                                        "dlSubdir": {-                                            "RegexDir": "^󽘋\u001d"-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "Experimental",-                                            "Latest",-                                            "LatestPrerelease",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:hdvmeb"-                                    }-                                },-                                "FreeBSD": {-                                    "( < 2.3.5 && > 4.4.4 && > 5.1.4 ) || ( == 4.1.2 && == 3.4.3 && > 2.1.2 && < 2.3.2 ) || ( >= 1.2.1 && >= 3.1.2 && > 2.1.3 )": {-                                        "dlCSize": -4,-                                        "dlHash": "nrwwht",-                                        "dlOutput": "",-                                        "dlSubdir": "𫺿􎻴rg\u001cZ",-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    },-                                    "( <= 3.5.1 && > 1.1.1 && > 4.5.2 && > 4.5.4 && <= 4.3.3 && > 3.3.5 && > 3.4.2 ) || ( > 2.1.2 && <= 1.2.2 && < 1.3.2 && < 2.3.3 ) || ( <= 2.1.3 ) || ( == 1.1.1 && < 2.1.2 && <= 2.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "zsmwen",-                                        "dlOutput": null,-                                        "dlSubdir": "z",-                                        "dlTag": [-                                            "Recommended",-                                            "Prerelease",-                                            "Experimental",-                                            "LatestNightly",-                                            "Prerelease",-                                            "Latest",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:fbpsc"-                                    },-                                    "( <= 5.1.2 && < 2.5.4 && >= 3.5.6 && <= 3.5.4 ) || ( < 3.3.2 && >= 2.1.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "azs",-                                        "dlOutput": "S",-                                        "dlSubdir": "\u001a\u0012𧙺󿼐\u0017\u0000",-                                        "dlTag": [-                                            "",-                                            "\u00120",-                                            "Recommended",-                                            "LatestNightly",-                                            "X𠣇\u0018쥷\\\u0014"-                                        ],-                                        "dlUri": "http:gcig"-                                    },-                                    "( >= 2.2.2 && == 1.2.1 && >= 3.5.5 && <= 4.1.4 && <= 5.3.1 )": {-                                        "dlCSize": 3,-                                        "dlHash": "gznp",-                                        "dlOutput": "\\0|\u0016m\"􄉮",-                                        "dlSubdir": "I",-                                        "dlTag": null,-                                        "dlUri": "http:ciuxtjl"-                                    },-                                    "( >= 3.2.4 && >= 4.5.3 && == 3.3.3 && < 4.2.5 && == 3.3.1 && < 4.3.1 )": {-                                        "dlCSize": 3,-                                        "dlHash": "eoacjxu",-                                        "dlOutput": ")x𣷭\u0011􄚀\u001b",-                                        "dlSubdir": {-                                            "RegexDir": "6󹞧]"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "LatestPrerelease",-                                            "LatestPrerelease",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:c"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -5,-                                        "dlHash": "ukhu",-                                        "dlOutput": null,-                                        "dlSubdir": "a9",-                                        "dlTag": null,-                                        "dlUri": "http:dzllg"-                                    }-                                },-                                "Linux_CentOS": {-                                    "( == 2.5.3 && >= 1.4.1 ) || ( <= 2.4.2 && >= 4.5.2 && > 2.3.3 && >= 3.1.3 && < 1.3.1 && >= 3.4.3 ) || ( == 3.1.1 && <= 2.1.2 && >= 3.2.1 && >= 3.1.2 ) || ( <= 2.1.1 && > 3.1.1 )": {-                                        "dlCSize": 2,-                                        "dlHash": "",-                                        "dlOutput": "\u0002\u000c\u0005\"tG",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Nightly",-                                            "old",-                                            "LatestPrerelease",-                                            "I"-                                        ],-                                        "dlUri": "https:hdl"-                                    }-                                },-                                "Linux_Debian": {},-                                "Windows": {-                                    "( < 1.5.1 && >= 4.5.5 && >= 2.2.4 )": {-                                        "dlCSize": -2,-                                        "dlHash": "tvf",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    },-                                    "( < 2.3.1 && > 2.4.2 && == 3.4.5 && > 4.4.4 && == 4.5.2 && >= 3.3.4 ) || ( <= 1.5.2 && > 4.3.1 && <= 2.3.2 && < 1.2.4 && >= 3.3.4 && >= 4.3.4 )": {-                                        "dlCSize": -7,-                                        "dlHash": "iwn",-                                        "dlOutput": "𡶘0𖨰!ㆸ󺰄",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [],-                                        "dlUri": "http:"-                                    },-                                    "( > 1.2.4 && < 6.2.3 && >= 2.2.2 ) || ( <= 2.3.3 ) || ( == 1.1.3 && < 1.3.2 && >= 2.1.2 ) || ( >= 2.1.1 && <= 2.1.2 )": {-                                        "dlCSize": -4,-                                        "dlHash": "h",-                                        "dlOutput": "",-                                        "dlSubdir": "VQ+W",-                                        "dlTag": null,-                                        "dlUri": "https:pzln"-                                    },-                                    "( > 2.1.5 && == 3.5.3 && > 1.1.3 && > 3.3.2 && <= 4.3.4 && <= 4.3.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "?𗈸|_R\u0008"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "base-5.3.2",-                                            "LatestNightly",-                                            "LatestPrerelease",-                                            "LatestPrerelease",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:gxzpkau"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -5,-                                        "dlHash": "yhn",-                                        "dlOutput": "\\7󴚰7",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "old",-                                            "Recommended",-                                            "old",-                                            "Latest",-                                            "Recommended",-                                            "old"-                                        ],-                                        "dlUri": "http:qyfpzss"-                                    }-                                }-                            },-                            "A_Sparc64": {-                                "FreeBSD": {-                                    "( <= 4.2.1 && <= 3.1.2 ) || ( >= 2.4.2 && <= 1.4.3 && < 1.3.2 && == 3.4.3 ) || ( == 3.2.3 && == 1.1.4 )": {-                                        "dlCSize": 1,-                                        "dlHash": "frf",-                                        "dlOutput": "󰧡ru\u0015",-                                        "dlSubdir": {-                                            "RegexDir": "'q냘>"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:zawah"-                                    },-                                    "( == 3.3.3 && == 3.1.4 && <= 3.3.4 && <= 3.1.4 && <= 4.2.1 && > 5.5.1 )": {-                                        "dlCSize": 2,-                                        "dlHash": "ftey",-                                        "dlOutput": "3\u000f",-                                        "dlSubdir": {-                                            "RegexDir": "%<\u000fuY"-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "LatestNightly",-                                            "LatestPrerelease",-                                            "Latest",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:oq"-                                    },-                                    "( > 4.2.2 && > 5.5.5 && < 2.1.2 && >= 1.4.1 && <= 1.1.5 && < 2.5.2 && < 1.2.5 ) || ( > 1.2.1 && < 4.1.3 && > 4.4.1 ) || ( > 1.3.1 && >= 1.2.3 && < 1.1.1 && <= 1.2.3 ) || ( == 2.2.1 && < 1.3.1 ) || ( <= 1.2.1 && > 1.2.1 && < 1.1.1 ) || ( < 1.2.1 )": {-                                        "dlCSize": -1,-                                        "dlHash": "hsnw",-                                        "dlOutput": "ꋸF\u0018Ya|",-                                        "dlSubdir": "",-                                        "dlTag": [],-                                        "dlUri": "http:bkfw"-                                    },-                                    "( > 5.2.2 && == 5.1.2 && >= 4.2.5 && <= 2.2.5 && < 6.6.3 && == 2.2.3 && == 4.4.3 ) || ( >= 1.3.2 && > 2.2.1 && > 1.2.2 && <= 3.4.2 ) || ( <= 3.3.2 && >= 2.3.3 && <= 3.3.1 && == 1.2.1 ) || ( == 1.1.1 && >= 2.2.2 && >= 2.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "zm",-                                        "dlOutput": "󳹊2",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:ojmsmv"-                                    },-                                    "( >= 4.1.4 && <= 1.3.5 && > 1.1.1 && < 2.5.3 && == 5.5.1 ) || ( > 4.2.2 ) || ( >= 2.1.1 && < 3.1.1 && <= 4.3.2 && < 1.1.1 && >= 1.2.3 ) || ( > 2.1.2 && <= 2.2.1 && <= 1.1.2 && < 2.4.1 ) || ( == 2.1.1 && >= 1.1.1 && <= 1.1.2 ) || ( <= 1.2.2 && > 1.2.1 ) || ( > 1.1.1 ) || ( >= 1.1.1 )": {-                                        "dlCSize": 1,-                                        "dlHash": "rht",-                                        "dlOutput": "%",-                                        "dlSubdir": "H",-                                        "dlTag": [-                                            "Recommended"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 2,-                                        "dlHash": "nwl",-                                        "dlOutput": "S&h+",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "old",-                                            "LatestNightly",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:blo"-                                    }-                                },-                                "Linux_Void": {-                                    "( < 1.2.3 && >= 5.4.4 && > 3.5.4 ) || ( < 1.5.2 && < 1.2.2 && <= 2.4.2 && <= 4.4.4 && < 4.3.1 && >= 4.4.4 ) || ( > 1.3.2 && > 3.1.1 && <= 1.1.3 )": {-                                        "dlCSize": 0,-                                        "dlHash": "s",-                                        "dlOutput": "䀛㸭\u0006",-                                        "dlSubdir": {-                                            "RegexDir": "󹋻\u0010x"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:guaiat"-                                    },-                                    "( <= 3.3.4 && == 3.1.3 )": {-                                        "dlCSize": -1,-                                        "dlHash": "tfihyxh",-                                        "dlOutput": "c􎣈\u0016𫋱M%^",-                                        "dlSubdir": "*",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Recommended",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:mhytnl"-                                    },-                                    "( > 2.2.4 && < 2.5.2 && > 5.2.1 && > 4.5.4 )": {-                                        "dlCSize": -3,-                                        "dlHash": "tmuf",-                                        "dlOutput": "g𨈱",-                                        "dlSubdir": {-                                            "RegexDir": "6WpZ󴠩"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:uunun"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 0,-                                        "dlHash": "xnxzwkm",-                                        "dlOutput": null,-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Nightly",-                                            "LatestNightly",-                                            "𦩪B\\"-                                        ],-                                        "dlUri": "https:"-                                    }-                                },-                                "Windows": {-                                    "( < 3.2.5 && >= 2.4.1 )": {-                                        "dlCSize": -4,-                                        "dlHash": "ujst",-                                        "dlOutput": "5i\"*[=W",-                                        "dlSubdir": {-                                            "RegexDir": "\r]4𣯈𓁑"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:vjzs"-                                    },-                                    "( <= 3.2.5 && <= 5.5.3 && >= 3.2.4 )": {-                                        "dlCSize": 2,-                                        "dlHash": "sx",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "LatestPrerelease",-                                            "",-                                            "base-1.4.2",-                                            "base-5.2.6",-                                            "Experimental",-                                            "Latest"-                                        ],-                                        "dlUri": "http:pmtmo"-                                    },-                                    "( == 2.5.4 && == 5.3.3 && <= 1.1.4 && >= 3.2.4 && < 5.3.4 && > 5.1.2 ) || ( >= 4.1.4 && < 2.1.2 && >= 1.2.2 && >= 2.4.1 && == 1.4.1 && >= 3.1.2 )": {-                                        "dlCSize": 5,-                                        "dlHash": "krhmi",-                                        "dlOutput": "0HC𣿡r)s",-                                        "dlSubdir": {-                                            "RegexDir": "/7 "-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:t"-                                    },-                                    "( == 3.4.1 && < 5.4.1 && == 3.1.3 && > 4.4.5 && >= 5.3.4 && <= 4.5.2 && >= 1.5.3 )": {-                                        "dlCSize": 2,-                                        "dlHash": "gcljafm",-                                        "dlOutput": "o",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "http:wnusahu"-                                    },-                                    "( > 3.2.2 && == 5.3.6 && < 5.5.4 && >= 4.3.3 && <= 3.4.2 && == 4.3.4 ) || ( > 2.4.1 && <= 4.3.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "dhm",-                                        "dlOutput": null,-                                        "dlSubdir": "E:𢀬L",-                                        "dlTag": [],-                                        "dlUri": "http:fj"-                                    },-                                    "( > 4.1.6 && >= 2.1.5 && > 1.3.1 && == 4.5.3 && <= 2.5.1 && <= 2.3.2 )": {-                                        "dlCSize": -5,-                                        "dlHash": "jna",-                                        "dlOutput": "[􎌍",-                                        "dlSubdir": "\u000e+w􎗩2",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "",-                                            "LatestNightly",-                                            "LatestNightly",-                                            "Latest",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:eb"-                                    },-                                    "( > 4.3.1 && > 2.2.2 && > 4.2.4 && < 4.4.2 ) || ( == 4.2.3 && <= 4.1.2 && >= 3.3.4 && >= 3.1.2 ) || ( < 1.1.2 && == 1.3.2 && >= 1.1.3 && == 3.1.1 && >= 2.2.2 )": {-                                        "dlCSize": 4,-                                        "dlHash": "kfjgqd",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Nightly",-                                            "Nightly",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:cnurnyl"-                                    }-                                }-                            }-                        },-                        "viChangeLog": "https:dew",-                        "viPostInstall": "qxtaqw",-                        "viPostRemove": null,-                        "viPreCompile": null,-                        "viPreInstall": "v",-                        "viReleaseDay": "-18790648527864394-12-26",-                        "viSourceDL": {-                            "dlCSize": -5,-                            "dlHash": "emc",-                            "dlOutput": null,-                            "dlSubdir": null,-                            "dlTag": [-                                "LatestPrerelease",-                                "LatestPrerelease",-                                "",-                                "Q\u001cj"-                            ],-                            "dlUri": "https:f"-                        },-                        "viTags": [-                            "]"-                        ],-                        "viTestDL": {-                            "dlCSize": null,-                            "dlHash": "jzsvl",-                            "dlOutput": "",-                            "dlSubdir": {-                                "RegexDir": "\u0007\u0011\u0008\u0008"-                            },-                            "dlTag": null,-                            "dlUri": "https:kg"-                        }-                    }-                },-                "GHCup": {-                    "4.6.4": {-                        "viArch": {-                            "A_ARM64": {-                                "Darwin": {-                                    "( == 5.4.2 && == 5.1.2 && == 5.2.2 && >= 1.1.1 ) || ( == 1.2.3 && >= 3.4.3 )": {-                                        "dlCSize": 6,-                                        "dlHash": "ggvkccn",-                                        "dlOutput": "q\u0007󳅦􇞳󻡕뻀%",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "㍨ꊥ[",-                                            "LatestNightly",-                                            "Latest"-                                        ],-                                        "dlUri": "http:m"-                                    },-                                    "( >= 2.5.4 && == 4.5.5 && <= 2.5.5 ) || ( == 2.3.1 && >= 1.2.3 && > 1.5.3 && > 4.3.1 )": {-                                        "dlCSize": 1,-                                        "dlHash": "ffdynd",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "H"-                                        },-                                        "dlTag": [-                                            "Recommended"-                                        ],-                                        "dlUri": "http:xkgtwg"-                                    }-                                },-                                "FreeBSD": {-                                    "( < 3.1.3 && >= 4.1.3 && == 3.4.1 && == 5.3.2 && == 3.4.2 && == 5.5.2 )": {-                                        "dlCSize": -2,-                                        "dlHash": "d",-                                        "dlOutput": "\u0011",-                                        "dlSubdir": "Y󴸪",-                                        "dlTag": [-                                            "Recommended",-                                            "old",-                                            "Prerelease",-                                            "\u001b󾅄$"-                                        ],-                                        "dlUri": "http:wx"-                                    },-                                    "( < 5.2.3 && == 1.4.2 && >= 3.1.1 && <= 5.4.5 ) || ( >= 1.3.1 && <= 4.4.3 && > 3.4.2 && <= 1.2.2 ) || ( > 2.1.3 && > 3.2.2 ) || ( > 1.2.2 && > 1.2.1 ) || ( >= 1.1.1 && <= 1.2.1 )": {-                                        "dlCSize": 2,-                                        "dlHash": "ocatngv",-                                        "dlOutput": "橽n",-                                        "dlSubdir": "둮󾸯\u0001",-                                        "dlTag": null,-                                        "dlUri": "https:derm"-                                    },-                                    "( == 5.5.1 && == 3.3.3 && == 1.5.4 && == 1.5.3 && <= 3.5.1 && >= 1.2.1 )": {-                                        "dlCSize": 4,-                                        "dlHash": "h",-                                        "dlOutput": "t",-                                        "dlSubdir": {-                                            "RegexDir": "9B\u0015}"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "old",-                                            "LatestPrerelease",-                                            "LatestPrerelease",-                                            "old"-                                        ],-                                        "dlUri": "http:gmgzjc"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 7,-                                        "dlHash": "amlpoga",-                                        "dlOutput": "*z􋉝\u000e\u0010",-                                        "dlSubdir": "􎫦\u0017d",-                                        "dlTag": [-                                            "Latest"-                                        ],-                                        "dlUri": "https:quqb"-                                    }-                                }-                            }-                        },-                        "viChangeLog": "https:mq",-                        "viPostInstall": null,-                        "viPostRemove": "dgpvm",-                        "viPreCompile": null,-                        "viPreInstall": "dsoxxea",-                        "viReleaseDay": "-19034419492295200-03-11",-                        "viSourceDL": null,-                        "viTags": [],-                        "viTestDL": {-                            "dlCSize": 3,-                            "dlHash": "ykdpi",-                            "dlOutput": "󺑶厍0",-                            "dlSubdir": {-                                "RegexDir": "𪒼jL"-                            },-                            "dlTag": [-                                "Recommended",-                                "Prerelease",-                                "Prerelease"-                            ],-                            "dlUri": "http:hsc"-                        }-                    },-                    "5.7.1": {-                        "viArch": {-                            "A_Sparc64": {-                                "FreeBSD": {-                                    "unknown_versioning": {-                                        "dlCSize": -1,-                                        "dlHash": "sij",-                                        "dlOutput": null,-                                        "dlSubdir": "剝!\u0013O􃞂$",-                                        "dlTag": [],-                                        "dlUri": "http:do"-                                    }-                                }-                            }-                        },-                        "viChangeLog": "https:mwwo",-                        "viPostInstall": null,-                        "viPostRemove": "vmyc",-                        "viPreCompile": "p",-                        "viPreInstall": null,-                        "viReleaseDay": null,-                        "viSourceDL": null,-                        "viTags": [-                            "Recommended",-                            "Nightly",-                            "Latest",-                            "LatestNightly"-                        ],-                        "viTestDL": {-                            "dlCSize": -6,-                            "dlHash": "uwkv",-                            "dlOutput": "[\u000cZ4",-                            "dlSubdir": {-                                "RegexDir": "𫢳n"-                            },-                            "dlTag": [-                                "LatestPrerelease"-                            ],-                            "dlUri": "http:vb"-                        }-                    },-                    "8.8.6": {-                        "viArch": {-                            "A_ARM": {-                                "Darwin": {-                                    "( < 1.4.2 ) || ( < 3.4.1 && < 1.4.1 ) || ( == 1.2.3 && > 2.2.3 )": {-                                        "dlCSize": -7,-                                        "dlHash": "vsoqdgl",-                                        "dlOutput": "󻑊𦃘\u0002𩮫\u0018",-                                        "dlSubdir": "\u0003𫆛𞋿\u0011%",-                                        "dlTag": [-                                            "Latest",-                                            "",-                                            "Latest"-                                        ],-                                        "dlUri": "https:be"-                                    },-                                    "( <= 1.1.4 ) || ( < 3.3.1 && == 4.4.3 && >= 1.4.4 && <= 2.1.4 && < 2.2.4 ) || ( == 3.2.2 && > 2.1.2 && == 3.2.1 && <= 2.2.2 ) || ( == 2.1.2 && >= 2.1.2 && <= 1.1.1 && == 1.1.2 )": {-                                        "dlCSize": 4,-                                        "dlHash": "pk",-                                        "dlOutput": "e,2\u0019",-                                        "dlSubdir": "Bj󱩗",-                                        "dlTag": null,-                                        "dlUri": "https:qcxotfq"-                                    },-                                    "( <= 1.4.4 && > 3.1.4 && <= 3.5.1 && >= 6.2.4 && == 4.5.1 && <= 1.2.1 && >= 5.5.3 )": {-                                        "dlCSize": -7,-                                        "dlHash": "cxl",-                                        "dlOutput": "",-                                        "dlSubdir": "󵖃oo",-                                        "dlTag": [],-                                        "dlUri": "http:jf"-                                    },-                                    "( == 1.2.3 && > 2.5.3 ) || ( >= 4.1.3 && == 3.3.1 && < 4.4.3 )": {-                                        "dlCSize": -1,-                                        "dlHash": "bxl",-                                        "dlOutput": "𬾨",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:ep"-                                    }-                                },-                                "FreeBSD": {-                                    "( < 4.2.4 && == 1.2.4 )": {-                                        "dlCSize": 2,-                                        "dlHash": "pplvyqh",-                                        "dlOutput": "dBR",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:zs"-                                    },-                                    "( <= 3.5.2 && < 4.5.4 && == 2.5.4 )": {-                                        "dlCSize": -4,-                                        "dlHash": "mfthpv",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Recommended",-                                            "􅒒T􆉚i"-                                        ],-                                        "dlUri": "https:ejvz"-                                    },-                                    "( > 2.1.2 ) || ( < 4.4.4 && > 1.3.1 ) || ( >= 2.3.1 && < 2.1.1 ) || ( < 1.1.2 )": {-                                        "dlCSize": -2,-                                        "dlHash": "zdxl",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "󳔲5{\u0016T7"-                                        },-                                        "dlTag": [-                                            "base-5.1.6",-                                            "base-6.5.1",-                                            "Experimental",-                                            "Prerelease",-                                            "Latest",-                                            "Prerelease",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:uplxp"-                                    },-                                    "( >= 2.4.2 && < 1.1.1 && > 2.3.4 && >= 2.5.5 && == 5.1.3 )": {-                                        "dlCSize": 0,-                                        "dlHash": "",-                                        "dlOutput": "T𗉈-",-                                        "dlSubdir": {-                                            "RegexDir": "3"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "Latest",-                                            "Recommended",-                                            "𱺔",-                                            "\u0007𗩖󱝒#-",-                                            "LatestPrerelease",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:ttf"-                                    },-                                    "( >= 3.5.2 && <= 2.2.3 && == 3.3.2 ) || ( == 4.3.4 && <= 3.4.4 && > 4.2.4 && == 1.3.5 && <= 2.2.2 ) || ( <= 3.3.2 && < 2.1.2 ) || ( <= 2.1.1 )": {-                                        "dlCSize": 6,-                                        "dlHash": "qizvnd",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "Za\u0019"-                                        },-                                        "dlTag": [-                                            "Nightly"-                                        ],-                                        "dlUri": "https:kdw"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -7,-                                        "dlHash": "awgrykd",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "坶"-                                        },-                                        "dlTag": [-                                            "Latest",-                                            "𫐥V+g􉠏",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:ojp"-                                    }-                                },-                                "Linux_OpenSUSE": {-                                    "( < 1.5.5 && >= 2.6.4 ) || ( <= 4.1.1 && == 1.4.4 && >= 1.1.3 && >= 2.3.1 && < 4.3.3 )": {-                                        "dlCSize": 6,-                                        "dlHash": "tnrzgar",-                                        "dlOutput": "𮩦~L",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:sat"-                                    },-                                    "( < 1.6.1 && > 1.4.1 && == 2.2.4 && >= 2.3.4 )": {-                                        "dlCSize": -3,-                                        "dlHash": "ehak",-                                        "dlOutput": "Y\"􏸥? *7",-                                        "dlSubdir": "pc\u000c",-                                        "dlTag": [],-                                        "dlUri": "https:pxbfsgz"-                                    },-                                    "( < 4.5.5 && <= 4.1.3 && >= 5.2.5 && <= 4.2.2 && >= 2.1.1 ) || ( >= 2.2.3 && >= 3.1.4 && == 4.2.2 && >= 4.3.1 && < 3.1.2 && > 4.1.4 ) || ( == 1.1.1 && == 2.1.3 && > 3.1.2 && <= 2.1.3 && >= 4.1.2 ) || ( < 3.1.2 && > 2.1.1 && >= 1.2.3 )": {-                                        "dlCSize": 3,-                                        "dlHash": "u",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "m􅟪𨚣"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:cmheb"-                                    },-                                    "( <= 1.1.5 && > 2.4.4 && < 5.2.3 && >= 4.4.4 && > 3.2.1 && == 5.6.5 && >= 2.2.1 ) || ( == 1.4.1 && <= 1.4.1 && >= 3.4.1 && >= 2.3.3 && > 2.3.3 )": {-                                        "dlCSize": -1,-                                        "dlHash": "lbcyxu",-                                        "dlOutput": "\u0003𢒬",-                                        "dlSubdir": {-                                            "RegexDir": "􇵌X𡾸^\u001d"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Latest",-                                            "Prerelease",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:dpng"-                                    },-                                    "( == 1.4.1 && < 2.5.5 && >= 4.2.3 ) || ( <= 4.3.3 && <= 3.4.4 && > 4.1.4 ) || ( < 3.2.3 && <= 3.2.2 && <= 3.2.4 )": {-                                        "dlCSize": -5,-                                        "dlHash": "uhxopjy",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:xbmem"-                                    },-                                    "( == 2.3.5 && > 4.2.5 && <= 4.1.5 && < 2.3.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": "\u001b",-                                        "dlTag": [-                                            "Prerelease",-                                            "LatestPrerelease",-                                            "old",-                                            "Latest",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:bfudzyy"-                                    },-                                    "( >= 4.5.3 && >= 1.4.1 && > 3.5.3 && >= 3.3.5 && > 3.5.5 && < 2.3.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": "hm,\\.",-                                        "dlSubdir": "",-                                        "dlTag": [],-                                        "dlUri": "https:ismkbcx"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "nhp",-                                        "dlOutput": "W\u000cy~랰",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:g"-                                    }-                                },-                                "Windows": {-                                    "( == 4.3.3 && > 5.5.1 && <= 5.5.1 && < 4.2.3 && < 4.2.2 && < 4.2.6 && > 4.5.1 )": {-                                        "dlCSize": -6,-                                        "dlHash": "gyuti",-                                        "dlOutput": "\u001a\u0006",-                                        "dlSubdir": {-                                            "RegexDir": "-}?R󰣜"-                                        },-                                        "dlTag": [-                                            "Recommended"-                                        ],-                                        "dlUri": "https:ug"-                                    },-                                    "( >= 1.5.2 && == 1.5.2 && < 4.1.3 ) || ( >= 3.1.3 && < 4.4.4 && >= 1.2.3 && > 1.1.1 && < 1.4.4 ) || ( < 3.2.3 && <= 2.3.3 && > 2.4.2 && < 1.3.3 ) || ( < 2.2.2 && == 1.1.1 && >= 1.1.1 && >= 1.1.2 )": {-                                        "dlCSize": 4,-                                        "dlHash": "ebcd",-                                        "dlOutput": "摚􆎇gjAz\u0019",-                                        "dlSubdir": {-                                            "RegexDir": "@}8l"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:vxahgo"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -2,-                                        "dlHash": "piqhfgz",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Experimental",-                                            "Latest",-                                            "LatestPrerelease",-                                            "old"-                                        ],-                                        "dlUri": "https:qk"-                                    }-                                }-                            },-                            "A_ARM64": {-                                "Linux_AmazonLinux": {-                                    "( < 3.2.3 && == 4.2.3 && >= 3.3.5 && == 1.2.2 )": {-                                        "dlCSize": -5,-                                        "dlHash": "nzos",-                                        "dlOutput": "eS(..",-                                        "dlSubdir": {-                                            "RegexDir": ")"-                                        },-                                        "dlTag": [-                                            "old",-                                            "Prerelease",-                                            "base-6.6.4",-                                            "Prerelease",-                                            "Experimental",-                                            "Latest",-                                            "base-1.5.2"-                                        ],-                                        "dlUri": "https:jnszxp"-                                    },-                                    "( <= 1.1.2 && <= 2.4.1 && <= 3.4.1 && >= 1.5.4 && == 3.2.5 && < 3.2.2 ) || ( < 1.4.4 && > 2.4.3 && > 1.1.4 && < 2.2.4 )": {-                                        "dlCSize": 5,-                                        "dlHash": "ncbjkf",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "http:gvootri"-                                    },-                                    "( <= 5.3.5 && < 5.5.2 && >= 2.1.1 && == 2.2.3 && < 1.3.5 ) || ( == 4.3.4 && >= 3.2.1 && <= 4.3.2 && == 5.4.1 && < 3.2.4 && > 4.1.4 ) || ( >= 3.1.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "trdvd",-                                        "dlOutput": "]\u0001持j",-                                        "dlSubdir": {-                                            "RegexDir": "衶󾛃k9\u0007"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "Latest",-                                            "Latest",-                                            "Recommended",-                                            "old"-                                        ],-                                        "dlUri": "http:tdf"-                                    },-                                    "( == 3.4.1 && == 4.4.5 && <= 2.3.3 && < 1.1.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "ffn",-                                        "dlOutput": "𰋹e",-                                        "dlSubdir": "𥹖b",-                                        "dlTag": [-                                            "\u000f\u0013\u0005",-                                            "base-4.5.3",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "( == 3.5.1 && < 3.4.4 ) || ( < 2.3.3 && > 5.3.3 ) || ( <= 4.1.3 && == 3.1.3 && > 2.1.2 && > 1.1.1 )": {-                                        "dlCSize": -7,-                                        "dlHash": "kwvwyh",-                                        "dlOutput": ">𗐕\u0014",-                                        "dlSubdir": {-                                            "RegexDir": "i\t"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "Nightly",-                                            "old",-                                            "\u0008",-                                            "LatestPrerelease",-                                            "󿯃_䒖󵩆\t"-                                        ],-                                        "dlUri": "https:zu"-                                    },-                                    "( > 1.6.3 && >= 4.4.2 && < 3.2.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "m",-                                        "dlOutput": "􍲨z:",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Experimental",-                                            "1\u0017􋮎b󰥨",-                                            "Experimental",-                                            "Experimental",-                                            "Qho,8",-                                            "Prerelease",-                                            "\u0000!\u0015"-                                        ],-                                        "dlUri": "https:njun"-                                    },-                                    "( >= 2.5.2 && <= 2.3.1 ) || ( <= 4.3.3 ) || ( <= 2.1.1 && < 3.2.3 && >= 2.3.3 && <= 3.3.3 && == 1.1.1 ) || ( >= 2.2.2 && > 2.2.1 && <= 1.2.2 && >= 2.3.1 )": {-                                        "dlCSize": 6,-                                        "dlHash": "s",-                                        "dlOutput": null,-                                        "dlSubdir": "b\u0018#&",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            ""-                                        ],-                                        "dlUri": "http:d"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "pwd",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "hX󳩂 \u0006J"-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "base-6.2.6",-                                            "LatestPrerelease",-                                            "Prerelease",-                                            "Latest",-                                            "Experimental",-                                            "base-6.4.2"-                                        ],-                                        "dlUri": "http:"-                                    }-                                },-                                "Linux_Rocky": {-                                    "( > 1.1.3 )": {-                                        "dlCSize": 7,-                                        "dlHash": "x",-                                        "dlOutput": ";\u0007l3WI󹿱",-                                        "dlSubdir": {-                                            "RegexDir": "`}r‟\u0004"-                                        },-                                        "dlTag": [-                                            "Recommended",-                                            "Prerelease",-                                            "Recommended",-                                            "Experimental",-                                            "old",-                                            "old",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:drj"-                                    },-                                    "( >= 1.5.2 && < 4.2.4 && > 4.2.2 && == 5.5.4 && < 5.1.5 )": {-                                        "dlCSize": -1,-                                        "dlHash": "nod",-                                        "dlOutput": null,-                                        "dlSubdir": "\u0004\u001e􇷰\u0003𘁯􀓢",-                                        "dlTag": [-                                            "old",-                                            "Latest",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:zsalcv"-                                    }-                                },-                                "Windows": {-                                    "( == 5.2.5 && == 4.1.4 && > 2.1.4 && == 4.3.3 && == 3.3.2 && >= 1.5.1 && == 5.6.2 ) || ( <= 4.1.1 && > 3.4.3 )": {-                                        "dlCSize": 3,-                                        "dlHash": "itcqa",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "\u0013c\"k𡮇\u001d"-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:q"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 7,-                                        "dlHash": "zvtbkrx",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "k\u001bI]1"-                                        },-                                        "dlTag": [-                                            "+畗􍻙",-                                            "LatestPrerelease",-                                            "old",-                                            "old",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:rysalju"-                                    }-                                }-                            },-                            "A_PowerPC64": {-                                "Darwin": {-                                    "( <= 2.3.1 && <= 5.1.2 && >= 5.3.3 ) || ( <= 4.4.4 )": {-                                        "dlCSize": 3,-                                        "dlHash": "bx",-                                        "dlOutput": "mE~f\u000b𦊾",-                                        "dlSubdir": {-                                            "RegexDir": "d\u001e󾡈'i\""-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:lsd"-                                    },-                                    "( <= 5.5.2 && > 3.4.4 ) || ( >= 4.4.1 && <= 4.3.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "tczq",-                                        "dlOutput": "r",-                                        "dlSubdir": "S?",-                                        "dlTag": [-                                            "old",-                                            "LatestNightly",-                                            "LatestNightly",-                                            "$\u0007im",-                                            "LatestNightly",-                                            "Latest",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:da"-                                    },-                                    "( == 4.5.2 && < 3.2.3 && >= 2.4.1 && < 2.1.2 )": {-                                        "dlCSize": 5,-                                        "dlHash": "flxjha",-                                        "dlOutput": "q󸓯n*\u0007<",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease",-                                            "Recommended",-                                            "Prerelease",-                                            "Recommended",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:zl"-                                    },-                                    "( > 5.3.4 && == 3.1.2 && > 3.3.1 && < 5.4.4 && < 1.2.4 ) || ( > 1.3.3 && <= 3.1.5 && >= 1.3.3 && > 4.4.4 && == 1.3.1 ) || ( <= 2.3.3 && > 1.1.1 )": {-                                        "dlCSize": -3,-                                        "dlHash": "",-                                        "dlOutput": "\u0001\u0010~𣉥𪞦\u0005S",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "http:w"-                                    },-                                    "( >= 1.1.1 && == 1.5.3 && < 2.4.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "tv",-                                        "dlOutput": "e0#􉤑d𒎑$",-                                        "dlSubdir": "\u000fO\n",-                                        "dlTag": [-                                            "Experimental",-                                            "LatestPrerelease",-                                            "Experimental",-                                            "Latest",-                                            "Prerelease",-                                            "LatestNightly",-                                            "old"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "( >= 1.5.3 && > 1.3.4 && <= 3.5.2 && <= 3.3.2 )": {-                                        "dlCSize": -4,-                                        "dlHash": "w",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "\u001e\u000e\u0015"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:mbp"-                                    },-                                    "( >= 4.3.4 && >= 5.5.3 && == 4.2.5 && >= 2.1.3 && <= 4.4.2 )": {-                                        "dlCSize": 7,-                                        "dlHash": "zf",-                                        "dlOutput": "G0i@.\u0015ﻇ",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "old",-                                            "base-1.1.5",-                                            "Prerelease",-                                            "Experimental",-                                            "LatestPrerelease",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:ftlweht"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -6,-                                        "dlHash": "cvpifx",-                                        "dlOutput": "𱭘D􈰰#ᇪ𩤶",-                                        "dlSubdir": {-                                            "RegexDir": "g\u001b󶌏\u0018"-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "LatestPrerelease",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:dgs"-                                    }-                                },-                                "FreeBSD": {},-                                "Linux_Mint": {-                                    "( < 4.2.4 && <= 1.5.5 && == 1.4.3 && <= 1.4.1 && <= 4.3.5 && <= 1.5.5 ) || ( <= 3.2.2 )": {-                                        "dlCSize": -3,-                                        "dlHash": "aocqrpm",-                                        "dlOutput": "L1I",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "Experimental"-                                        ],-                                        "dlUri": "https:dr"-                                    },-                                    "( <= 3.5.3 && >= 1.1.3 && >= 1.3.2 ) || ( > 1.3.2 && <= 3.2.1 && >= 3.2.4 && == 3.1.4 && > 1.2.1 && == 2.5.4 ) || ( < 3.1.2 && <= 3.3.3 && == 2.4.2 && >= 1.1.2 )": {-                                        "dlCSize": 2,-                                        "dlHash": "rl",-                                        "dlOutput": "n",-                                        "dlSubdir": {-                                            "RegexDir": "\"i"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:hyelox"-                                    }-                                }-                            },-                            "A_Sparc": {-                                "FreeBSD": {-                                    "( < 2.2.4 && <= 3.2.2 && > 4.5.1 && >= 5.6.3 && < 5.2.5 ) || ( > 2.2.1 && > 3.2.3 && == 5.4.3 && >= 4.3.4 && <= 2.4.2 && <= 2.4.3 )": {-                                        "dlCSize": -3,-                                        "dlHash": "krke",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "N#"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "base-6.1.3",-                                            "LatestNightly",-                                            "LatestNightly",-                                            "Latest"-                                        ],-                                        "dlUri": "https:d"-                                    },-                                    "( < 4.1.5 && >= 3.3.6 && == 5.5.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "dawi",-                                        "dlOutput": "/\u0016",-                                        "dlSubdir": "󷦬\u001fb^",-                                        "dlTag": null,-                                        "dlUri": "https:"-                                    },-                                    "( <= 4.4.3 && < 5.4.5 && <= 4.4.5 && < 5.2.5 && > 4.3.2 && == 2.5.1 )": {-                                        "dlCSize": -3,-                                        "dlHash": "ors",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:jtf"-                                    },-                                    "( == 1.3.2 && <= 3.2.4 && > 5.2.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "u",-                                        "dlOutput": "l0",-                                        "dlSubdir": "𩽺",-                                        "dlTag": [-                                            "Nightly",-                                            "J>"-                                        ],-                                        "dlUri": "http:oufgls"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -7,-                                        "dlHash": "hskzni",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "1J"-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "𩕈󷦴x",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:gdqvkhu"-                                    }-                                },-                                "Linux_Mint": {-                                    "unknown_versioning": {-                                        "dlCSize": 3,-                                        "dlHash": "liy",-                                        "dlOutput": null,-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "U",-                                            "Latest",-                                            "{꧍\u000e\u0014",-                                            "base-2.5.2",-                                            "LatestNightly",-                                            "Experimental",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:e"-                                    }-                                },-                                "Windows": {-                                    "( <= 1.3.2 && < 2.4.1 && >= 3.4.1 && >= 3.2.4 && > 2.4.4 ) || ( == 1.3.3 && <= 1.2.2 && < 2.4.3 && > 1.3.3 && > 1.3.3 && > 1.1.2 )": {-                                        "dlCSize": -5,-                                        "dlHash": "t",-                                        "dlOutput": "󼒐)>􉏊᧿\u001e",-                                        "dlSubdir": {-                                            "RegexDir": "{7\u000cFP"-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "\u000e",-                                            "LatestNightly",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:vkhym"-                                    },-                                    "( <= 3.4.4 && == 3.1.4 && >= 1.1.4 && == 3.2.2 && > 5.3.3 )": {-                                        "dlCSize": 0,-                                        "dlHash": "ee",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Experimental",-                                            "Experimental",-                                            "Experimental",-                                            "LatestNightly",-                                            ";%\u0011𤢰",-                                            "base-3.5.2",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:fzz"-                                    },-                                    "( == 1.5.2 && == 2.4.3 && >= 2.4.4 && == 1.4.3 && > 1.1.5 ) || ( >= 1.3.4 && == 2.1.3 && == 2.4.3 && == 4.2.4 && == 2.2.3 ) || ( == 3.1.2 )": {-                                        "dlCSize": 1,-                                        "dlHash": "tfsf",-                                        "dlOutput": "\u0014{g}&D䳬",-                                        "dlSubdir": {-                                            "RegexDir": "ৈ"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Experimental",-                                            "LatestNightly",-                                            "Experimental",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:ss"-                                    },-                                    "( > 2.1.4 && < 5.4.3 && < 2.5.1 && <= 2.5.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "y",-                                        "dlOutput": "\u001f7\u0001󱮿>0L",-                                        "dlSubdir": {-                                            "RegexDir": "u4\u0000\u000c󼹛􋉦"-                                        },-                                        "dlTag": [-                                            "Recommended",-                                            "base-6.1.1"-                                        ],-                                        "dlUri": "https:vegtdum"-                                    },-                                    "( > 3.5.5 && < 4.1.2 && < 5.3.2 && >= 4.4.3 ) || ( >= 3.2.1 && == 4.3.4 && < 2.4.4 && == 2.2.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "ew",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "Recommended",-                                            "old",-                                            "LatestNightly",-                                            "Recommended",-                                            "Experimental",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:aau"-                                    },-                                    "( >= 1.4.6 && >= 4.3.2 )": {-                                        "dlCSize": 3,-                                        "dlHash": "dk",-                                        "dlOutput": "𣄹󽝙w",-                                        "dlSubdir": "L\r署󱦽e\u0002",-                                        "dlTag": [-                                            "base-2.4.3",-                                            "old",-                                            "Recommended",-                                            "Recommended",-                                            "old"-                                        ],-                                        "dlUri": "http:arzg"-                                    }-                                }-                            }-                        },-                        "viChangeLog": "http:dphbion",-                        "viPostInstall": "",-                        "viPostRemove": null,-                        "viPreCompile": "i",-                        "viPreInstall": null,-                        "viReleaseDay": "12597021425758112-08-30",-                        "viSourceDL": {-                            "dlCSize": null,-                            "dlHash": "ofc",-                            "dlOutput": "",-                            "dlSubdir": null,-                            "dlTag": [-                                "Nightly",-                                "Experimental",-                                "Recommended"-                            ],-                            "dlUri": "http:orv"-                        },-                        "viTags": [-                            "base-3.5.4",-                            "Recommended",-                            "-",-                            "base-1.3.6"-                        ],-                        "viTestDL": {-                            "dlCSize": 1,-                            "dlHash": "eg",-                            "dlOutput": "'󾺷T\u0008.",-                            "dlSubdir": {-                                "RegexDir": "h✾,."-                            },-                            "dlTag": [-                                "base-3.1.2",-                                "Nightly"-                            ],-                            "dlUri": "https:dh"-                        }-                    }-                },-                "HLS": {-                    "3.1.7": {-                        "viArch": {-                            "A_32": {},-                            "A_PowerPC": {-                                "Darwin": {-                                    "( <= 3.5.3 && <= 3.2.5 && <= 2.2.2 && >= 4.5.2 && > 1.1.5 && > 2.3.1 )": {-                                        "dlCSize": -1,-                                        "dlHash": "zhdjfn",-                                        "dlOutput": "Yq",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:u"-                                    },-                                    "( <= 4.2.3 )": {-                                        "dlCSize": -6,-                                        "dlHash": "awngwr",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:ova"-                                    },-                                    "( > 3.2.5 && == 3.5.1 && >= 4.3.5 && < 4.4.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "jier",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "base-4.3.8",-                                            "\t󹍵K",-                                            "Latest",-                                            "Latest",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:div"-                                    }-                                }-                            },-                            "A_PowerPC64": {-                                "Darwin": {},-                                "FreeBSD": {-                                    "( <= 4.4.4 && == 1.5.5 && == 2.6.2 && < 5.1.5 ) || ( > 4.2.1 && < 4.1.4 && == 4.4.4 )": {-                                        "dlCSize": -4,-                                        "dlHash": "akhcqcq",-                                        "dlOutput": "𰄔𱙲HT",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "http:xdefsuy"-                                    },-                                    "( > 2.2.5 ) || ( == 4.5.4 )": {-                                        "dlCSize": -4,-                                        "dlHash": "t",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": ",\u0003\"-"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:fyp"-                                    },-                                    "( > 5.2.2 && <= 5.3.2 && == 5.2.4 && <= 4.1.3 && < 5.3.5 && > 4.1.5 )": {-                                        "dlCSize": -7,-                                        "dlHash": "e",-                                        "dlOutput": "\u0008K",-                                        "dlSubdir": "qF",-                                        "dlTag": null,-                                        "dlUri": "http:prypbz"-                                    },-                                    "( >= 2.1.4 ) || ( <= 4.1.3 && > 3.4.1 && >= 4.2.4 ) || ( <= 1.3.1 && == 3.2.1 && >= 2.1.2 && < 2.2.2 && == 1.2.1 )": {-                                        "dlCSize": 4,-                                        "dlHash": "py",-                                        "dlOutput": "H􊾫z􄐑󰞴O",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 6,-                                        "dlHash": "mww",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "\u0010\u000f\u0006󺺃"-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "old",-                                            "Latest",-                                            "LatestNightly",-                                            "Recommended",-                                            "\u001d[􋰊Wlo",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:w"-                                    }-                                },-                                "Linux_CentOS": {-                                    "( < 3.1.5 ) || ( < 3.3.4 && <= 2.1.2 && < 5.2.1 ) || ( <= 1.3.3 && > 1.3.4 )": {-                                        "dlCSize": 6,-                                        "dlHash": "yinvusc",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "r"-                                        },-                                        "dlTag": [-                                            "Recommended",-                                            "Prerelease",-                                            "LatestNightly",-                                            "old"-                                        ],-                                        "dlUri": "https:ewobz"-                                    },-                                    "( == 1.4.3 && <= 4.1.4 && == 5.5.1 && == 3.1.4 && < 3.5.5 && < 2.1.5 ) || ( > 3.3.3 && >= 4.2.4 && > 2.3.3 ) || ( > 1.3.2 && >= 2.2.2 )": {-                                        "dlCSize": 3,-                                        "dlHash": "iewtqz",-                                        "dlOutput": null,-                                        "dlSubdir": "􂱌",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Nightly",-                                            "Experimental",-                                            "Nightly",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:snbslu"-                                    },-                                    "( == 2.1.3 && < 2.3.4 ) || ( == 2.1.1 && == 2.2.1 && > 3.5.1 && <= 1.3.1 && < 4.1.2 ) || ( >= 2.3.2 && >= 2.4.2 && > 3.3.1 && >= 2.1.2 && == 2.2.4 )": {-                                        "dlCSize": 1,-                                        "dlHash": "zhslh",-                                        "dlOutput": "jy\twR^%",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Nightly",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:hqao"-                                    },-                                    "( == 5.5.2 && >= 2.5.6 && > 5.4.3 && == 5.2.5 && > 4.1.3 && < 5.4.1 ) || ( <= 2.2.4 ) || ( >= 1.2.2 && >= 3.1.2 && >= 1.1.4 && < 3.1.3 && > 2.2.2 )": {-                                        "dlCSize": -3,-                                        "dlHash": "htshdwm",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "0􄸊 𥳟,R"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:mq"-                                    },-                                    "( > 6.2.3 && == 2.2.4 && == 3.5.4 && < 1.5.5 && < 5.2.1 ) || ( == 4.1.4 && == 1.1.3 && < 1.4.2 ) || ( <= 2.2.1 && == 1.3.4 && <= 3.1.3 ) || ( <= 1.2.1 && > 1.2.1 ) || ( >= 2.1.1 && >= 2.1.1 && > 1.2.1 ) || ( < 1.1.1 && == 1.1.1 )": {-                                        "dlCSize": 3,-                                        "dlHash": "fnqh",-                                        "dlOutput": "뢿(",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "LatestNightly",-                                            "LatestPrerelease",-                                            "Latest",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( >= 5.5.5 && == 5.1.4 && < 4.3.1 && == 4.3.2 && > 3.2.3 )": {-                                        "dlCSize": 0,-                                        "dlHash": "ye",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "𠛟𭧧𗰏A"-                                        },-                                        "dlTag": [-                                            "old",-                                            "\u0004",-                                            "LatestNightly",-                                            "base-3.4.5",-                                            "Experimental",-                                            "",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:nnt"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -1,-                                        "dlHash": "a",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:grvdw"-                                    }-                                },-                                "Linux_Exherbo": {-                                    "( >= 5.3.4 && <= 2.2.1 && <= 5.1.2 && <= 5.3.2 && >= 1.4.4 && > 4.4.2 && <= 1.1.5 )": {-                                        "dlCSize": 4,-                                        "dlHash": "nyyimps",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "7\u0018ᕢ𪕪"-                                        },-                                        "dlTag": [-                                            "",-                                            "LatestNightly",-                                            "Experimental",-                                            "old",-                                            "Latest",-                                            "Prerelease",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:xvnqiwk"-                                    }-                                },-                                "Windows": {-                                    "( > 2.1.5 && > 5.1.1 && >= 2.3.4 && <= 1.3.1 )": {-                                        "dlCSize": -3,-                                        "dlHash": "dzqbkd",-                                        "dlOutput": "ಜZ\u0019",-                                        "dlSubdir": {-                                            "RegexDir": "/"-                                        },-                                        "dlTag": [-                                            "Recommended",-                                            "base-2.1.5",-                                            "Experimental",-                                            "Nightly",-                                            "LatestPrerelease",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:k"-                                    },-                                    "( > 2.4.5 && > 5.3.4 && < 3.4.1 && >= 3.2.2 ) || ( == 4.1.4 && < 3.1.3 && >= 3.4.3 && >= 2.4.2 && == 4.3.1 && > 5.1.3 ) || ( <= 2.1.3 && == 1.1.1 && > 3.2.2 && > 3.1.3 )": {-                                        "dlCSize": -4,-                                        "dlHash": "io",-                                        "dlOutput": "U𜾄T\u0003\u001f\u0016",-                                        "dlSubdir": "laH.",-                                        "dlTag": [],-                                        "dlUri": "https:"-                                    },-                                    "( >= 1.2.4 && > 4.3.5 )": {-                                        "dlCSize": -3,-                                        "dlHash": "lwwvx",-                                        "dlOutput": "푖4=䡏V\u0003",-                                        "dlSubdir": "􍔯<",-                                        "dlTag": [-                                            "밃",-                                            "Prerelease",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:j"-                                    },-                                    "( >= 2.5.1 && >= 4.2.3 && < 4.1.2 && <= 4.3.3 ) || ( <= 3.2.1 && < 4.4.4 && >= 2.1.2 && == 4.1.1 && <= 3.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "yxq",-                                        "dlOutput": "u􈈲\"\u0012A",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Experimental",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:wrkwn"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 6,-                                        "dlHash": "",-                                        "dlOutput": "\u001eU4E",-                                        "dlSubdir": "\u0004磶}bi2",-                                        "dlTag": [-                                            "Recommended",-                                            "33lU",-                                            "Experimental",-                                            "Recommended",-                                            "Nightly",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:"-                                    }-                                }-                            },-                            "A_Sparc64": {-                                "Darwin": {-                                    "( < 6.5.2 && <= 2.1.2 && == 3.4.4 && > 3.2.2 && == 1.5.2 )": {-                                        "dlCSize": 4,-                                        "dlHash": "ahka",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "%\u0017",-                                            "Prerelease",-                                            "base-4.3.6",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:ehmpkj"-                                    },-                                    "( <= 5.2.4 && <= 1.1.2 && <= 4.5.1 && >= 3.3.5 && > 1.1.1 && < 4.3.5 && < 4.5.4 ) || ( < 3.3.4 && <= 2.1.2 && <= 2.1.4 && <= 2.4.3 ) || ( > 1.2.3 ) || ( >= 2.1.2 )": {-                                        "dlCSize": 4,-                                        "dlHash": "zfgbr",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "8\u001e\u0015E",-                                            "",-                                            "Latest",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:sjdkg"-                                    },-                                    "( == 5.1.2 && == 1.2.6 && >= 1.4.2 && < 4.3.2 ) || ( >= 3.4.2 && <= 4.4.1 && <= 2.2.4 && <= 4.3.1 ) || ( > 1.3.1 && > 1.2.3 && >= 3.1.2 ) || ( == 2.2.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "zaxhubp",-                                        "dlOutput": "B𓍘",-                                        "dlSubdir": "𱬤𠔵B",-                                        "dlTag": [-                                            "base-1.4.1",-                                            "Prerelease",-                                            "Prerelease",-                                            "LatestNightly",-                                            "Experimental",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:ynmn"-                                    },-                                    "( > 5.1.5 && > 1.3.4 ) || ( == 2.2.4 && > 2.2.1 && == 2.1.4 && >= 2.3.3 && == 4.2.4 && > 4.4.2 ) || ( >= 1.2.1 && > 2.3.3 && < 2.3.2 && >= 3.1.2 && <= 1.1.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": "h\u0010:\u0001\u0015뤘",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "old"-                                        ],-                                        "dlUri": "http:owsu"-                                    },-                                    "( >= 1.1.2 && > 5.5.4 && > 5.2.1 ) || ( > 3.3.4 && == 3.4.4 && >= 5.1.4 && <= 4.2.2 && == 2.4.2 ) || ( < 1.1.3 && <= 3.2.2 && > 2.2.3 && <= 2.1.1 && <= 1.1.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "kq",-                                        "dlOutput": "􊻒􃎆%",-                                        "dlSubdir": {-                                            "RegexDir": "\u001f"-                                        },-                                        "dlTag": [-                                            "base-3.1.4",-                                            "Recommended",-                                            "Recommended",-                                            "Experimental",-                                            "old",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:zpnhx"-                                    },-                                    "( >= 2.1.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "mi",-                                        "dlOutput": "",-                                        "dlSubdir": "g;g\u0014#",-                                        "dlTag": [-                                            "old",-                                            "old",-                                            "base-6.2.6"-                                        ],-                                        "dlUri": "http:v"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -4,-                                        "dlHash": "h",-                                        "dlOutput": "lF᳢P&)",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "6"-                                        ],-                                        "dlUri": "http:av"-                                    }-                                },-                                "FreeBSD": {-                                    "( <= 1.1.3 && == 4.5.2 && < 3.1.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "wzv",-                                        "dlOutput": "",-                                        "dlSubdir": "1󿈁",-                                        "dlTag": [-                                            "J\u0014K\u0000p뭎",-                                            "Experimental",-                                            "Latest",-                                            "Prerelease",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:iszerz"-                                    },-                                    "( <= 1.1.5 )": {-                                        "dlCSize": -5,-                                        "dlHash": "a",-                                        "dlOutput": ";9",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "Experimental",-                                            "base-4.2.1",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:rylimrq"-                                    },-                                    "( == 2.4.2 && < 4.1.4 && == 3.3.2 && >= 5.2.3 && > 2.4.1 && <= 3.4.1 && >= 3.4.3 )": {-                                        "dlCSize": 7,-                                        "dlHash": "nfw",-                                        "dlOutput": "2oMom",-                                        "dlSubdir": {-                                            "RegexDir": "\u0008𱔌v\u001f"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "Recommended",-                                            "\t=\u0004J󶇢",-                                            "x\r󹔮𥊊qP",-                                            "base-1.4.3",-                                            "base-1.5.6",-                                            "Latest"-                                        ],-                                        "dlUri": "http:umzwger"-                                    },-                                    "( > 1.4.2 && < 1.1.4 && > 2.2.5 ) || ( == 1.4.2 && > 4.2.1 && <= 2.1.2 && == 1.4.3 && == 3.4.1 && == 2.4.2 )": {-                                        "dlCSize": 0,-                                        "dlHash": "fwsge",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "base-4.5.4",-                                            "Nightly",-                                            "Prerelease",-                                            "LatestPrerelease",-                                            "Experimental",-                                            "base-5.7.3"-                                        ],-                                        "dlUri": "http:wmjzdk"-                                    },-                                    "( > 3.1.5 && < 5.5.4 && <= 2.4.5 && > 1.2.1 && >= 1.5.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "vbba",-                                        "dlOutput": null,-                                        "dlSubdir": "4\u0017O󰅿",-                                        "dlTag": [-                                            "Experimental",-                                            "LatestNightly",-                                            "LatestNightly",-                                            "Latest"-                                        ],-                                        "dlUri": "https:autp"-                                    },-                                    "( >= 1.3.4 && < 1.3.2 && == 2.4.4 && > 2.6.4 ) || ( == 4.3.1 && <= 3.2.2 && > 3.5.1 && < 2.1.3 && > 3.1.2 && < 4.2.3 )": {-                                        "dlCSize": 1,-                                        "dlHash": "g",-                                        "dlOutput": "&",-                                        "dlSubdir": {-                                            "RegexDir": "\u000b\u0016𢆔A📸𠌬"-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:lrht"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 4,-                                        "dlHash": "ztxtpc",-                                        "dlOutput": "!,𤌊뢋󶴱\u000fE",-                                        "dlSubdir": "^\u0017󹂐|x",-                                        "dlTag": null,-                                        "dlUri": "http:aofpq"-                                    }-                                },-                                "Windows": {-                                    "( == 2.2.4 )": {-                                        "dlCSize": -1,-                                        "dlHash": "qcq",-                                        "dlOutput": "",-                                        "dlSubdir": "NO\u000e",-                                        "dlTag": [-                                            "base-5.2.6",-                                            "LatestNightly",-                                            "Latest",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:rq"-                                    },-                                    "( > 2.5.5 && < 4.1.3 ) || ( > 4.1.2 && == 2.2.2 && >= 3.3.1 && >= 4.4.5 && <= 2.3.3 && == 2.4.2 ) || ( <= 2.2.2 ) || ( >= 1.2.1 )": {-                                        "dlCSize": 0,-                                        "dlHash": "xkk",-                                        "dlOutput": "촫08\u0000",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:m"-                                    },-                                    "( >= 4.2.3 && == 2.6.4 && >= 3.1.2 && > 6.2.4 && < 2.2.3 && < 3.1.3 ) || ( < 4.3.1 && < 4.3.1 && >= 3.3.2 ) || ( < 3.2.2 && == 1.3.3 && >= 2.1.3 && >= 1.1.2 && == 3.2.1 ) || ( < 1.2.1 && > 1.1.1 && < 3.1.1 ) || ( <= 1.1.2 ) || ( > 1.2.2 ) || ( <= 1.1.1 )": {-                                        "dlCSize": 7,-                                        "dlHash": "k",-                                        "dlOutput": null,-                                        "dlSubdir": ";",-                                        "dlTag": [-                                            "Prerelease",-                                            "R",-                                            "LatestPrerelease",-                                            "Recommended",-                                            "LatestPrerelease",-                                            "Nightly",-                                            "Latest"-                                        ],-                                        "dlUri": "https:ss"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -4,-                                        "dlHash": "ntjck",-                                        "dlOutput": "b9",-                                        "dlSubdir": {-                                            "RegexDir": "b\u0012年"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:huf"-                                    }-                                }-                            }-                        },-                        "viChangeLog": "http:gsmbxe",-                        "viPostInstall": "sstfo",-                        "viPostRemove": "whb",-                        "viPreCompile": null,-                        "viPreInstall": null,-                        "viReleaseDay": "-18208623040331981-12-07",-                        "viSourceDL": null,-                        "viTags": [-                            "Nightly"-                        ],-                        "viTestDL": {-                            "dlCSize": 1,-                            "dlHash": "pyamm",-                            "dlOutput": "rz\u0005",-                            "dlSubdir": "\u000eO",-                            "dlTag": [-                                "Latest"-                            ],-                            "dlUri": "https:oxrzu"-                        }-                    },-                    "8.8.2": {-                        "viArch": {-                            "A_ARM64": {-                                "Darwin": {-                                    "( <= 1.3.4 && <= 4.1.2 && >= 3.1.1 && < 5.5.1 && >= 4.1.5 && > 3.4.2 ) || ( < 3.1.4 && >= 2.4.2 ) || ( >= 2.2.1 && > 1.3.2 && > 1.3.2 && > 2.1.3 && > 1.1.3 )": {-                                        "dlCSize": 6,-                                        "dlHash": "yvjs",-                                        "dlOutput": "x\u0006tiI",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Nightly",-                                            "Experimental",-                                            "old",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:kdofah"-                                    },-                                    "( == 1.5.1 && <= 2.1.5 && == 1.5.4 ) || ( < 3.1.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "fi",-                                        "dlOutput": "8f:N`𗧼𬻘",-                                        "dlSubdir": {-                                            "RegexDir": "𰇹"-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "Prerelease",-                                            "Nightly",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:j"-                                    }-                                },-                                "FreeBSD": {},-                                "Linux_Fedora": {-                                    "( < 1.3.6 ) || ( > 5.3.1 && < 3.1.4 && > 3.4.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "kqg",-                                        "dlOutput": "􏔖􅢩i󸜆N\u0011\t",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Latest",-                                            "Prerelease",-                                            "LatestPrerelease",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:wfujvlt"-                                    },-                                    "( < 3.3.5 && < 3.1.3 && == 3.3.2 && < 2.1.4 && <= 5.5.5 && < 1.1.4 && <= 4.5.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "xncfr",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "䮋N"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Latest",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "d",-                                        "dlOutput": "4&u\nX􄸖(",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Latest"-                                        ],-                                        "dlUri": "https:hv"-                                    }-                                },-                                "Linux_Mint": {-                                    "( <= 2.4.5 ) || ( >= 2.2.4 && == 1.4.1 ) || ( == 3.1.1 && == 3.4.2 ) || ( == 1.2.2 && == 1.2.1 && < 2.2.2 ) || ( < 1.1.1 && >= 1.1.1 && > 1.1.1 ) || ( == 1.1.1 && < 1.1.1 )": {-                                        "dlCSize": 1,-                                        "dlHash": "z",-                                        "dlOutput": null,-                                        "dlSubdir": "M0",-                                        "dlTag": [-                                            "old",-                                            "LatestNightly",-                                            "Recommended",-                                            "Prerelease",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:on"-                                    },-                                    "( <= 4.3.4 && >= 4.2.6 && >= 5.3.4 && >= 1.3.2 && > 1.3.3 ) || ( > 4.3.2 && >= 1.2.1 && == 1.4.4 ) || ( <= 2.2.2 && == 1.1.4 && <= 1.1.2 && == 1.1.2 ) || ( > 2.2.3 && <= 2.2.2 && <= 1.2.2 && > 2.1.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "lrfmlyn",-                                        "dlOutput": "V",-                                        "dlSubdir": "qo",-                                        "dlTag": [-                                            "Experimental"-                                        ],-                                        "dlUri": "https:wm"-                                    },-                                    "( == 2.2.2 && == 5.6.5 ) || ( == 4.1.1 && >= 4.4.1 && > 1.1.4 && < 4.1.2 && > 1.2.1 ) || ( > 2.2.3 && == 1.4.3 && == 2.1.1 )": {-                                        "dlCSize": 4,-                                        "dlHash": "ya",-                                        "dlOutput": null,-                                        "dlSubdir": "&J",-                                        "dlTag": null,-                                        "dlUri": "https:pfxrjwp"-                                    },-                                    "( == 3.1.3 && > 2.1.1 ) || ( == 1.1.3 ) || ( < 2.1.3 && == 2.3.2 && < 1.1.2 && >= 2.3.2 ) || ( == 2.1.2 && == 2.2.1 && > 2.1.2 )": {-                                        "dlCSize": 0,-                                        "dlHash": "lodktw",-                                        "dlOutput": "I􎞩\u000c",-                                        "dlSubdir": {-                                            "RegexDir": "-Xu𠒛𰺦"-                                        },-                                        "dlTag": [-                                            "􊲁9j)"-                                        ],-                                        "dlUri": "https:huezccd"-                                    },-                                    "( >= 3.6.1 && <= 1.2.2 && <= 2.5.2 && > 1.1.1 && <= 2.1.5 && >= 5.2.2 && >= 5.3.6 ) || ( <= 1.2.1 && >= 1.4.4 && == 5.4.2 && >= 4.1.2 && <= 3.5.1 )": {-                                        "dlCSize": -5,-                                        "dlHash": "cf",-                                        "dlOutput": "j\u0010]",-                                        "dlSubdir": {-                                            "RegexDir": "𮈧\u0000\tqr{"-                                        },-                                        "dlTag": [-                                            "Recommended",-                                            "old",-                                            "old",-                                            "base-2.5.6",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:hj"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "jsnjdu",-                                        "dlOutput": "W\u000e'􀓩⟌䰯",-                                        "dlSubdir": "v低\u000f",-                                        "dlTag": null,-                                        "dlUri": "https:mu"-                                    }-                                },-                                "Windows": {-                                    "( < 3.1.6 && == 1.3.3 && > 4.5.2 && <= 2.2.3 && > 1.1.4 )": {-                                        "dlCSize": -1,-                                        "dlHash": "ttwbj",-                                        "dlOutput": "\u0010󲸒\u0004\u0010R_",-                                        "dlSubdir": "uL",-                                        "dlTag": [-                                            "LatestNightly",-                                            "Recommended",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:vnwda"-                                    },-                                    "( <= 3.2.4 && >= 3.3.3 && >= 2.5.1 && == 1.2.3 && <= 3.1.1 && == 5.3.2 && <= 1.5.3 )": {-                                        "dlCSize": 2,-                                        "dlHash": "",-                                        "dlOutput": "e",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "}骿󱿶o "-                                        ],-                                        "dlUri": "http:ncknwu"-                                    },-                                    "( <= 3.5.2 && < 3.1.1 && <= 4.1.3 ) || ( < 3.1.4 && < 4.2.1 && == 2.4.1 && < 2.3.3 )": {-                                        "dlCSize": -4,-                                        "dlHash": "pemfz",-                                        "dlOutput": "TvyG",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:zazrt"-                                    },-                                    "( <= 3.6.1 && > 3.1.5 && <= 5.2.5 && <= 3.1.1 && >= 2.4.3 )": {-                                        "dlCSize": 4,-                                        "dlHash": "vehnciz",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "|𬝢"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    },-                                    "( > 1.3.2 && < 3.5.2 && == 1.2.6 && == 5.2.2 && <= 5.4.1 && == 3.2.3 )": {-                                        "dlCSize": 6,-                                        "dlHash": "tcqs",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": " "-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:fpabg"-                                    },-                                    "( > 1.4.3 && == 1.4.2 && <= 1.2.5 && >= 3.4.4 ) || ( > 1.1.2 && < 3.2.3 && == 2.2.2 && == 2.5.2 && >= 2.4.3 ) || ( > 1.3.1 && > 3.2.2 && >= 1.2.1 && > 3.1.2 ) || ( > 3.1.3 && <= 2.2.3 && <= 3.1.4 ) || ( >= 1.2.1 && < 1.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "z",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "~v\u0000q"-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:jzdjr"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 0,-                                        "dlHash": "",-                                        "dlOutput": "\u001d􃚈󴒲E%",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "old",-                                            "old",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:i"-                                    }-                                }-                            },-                            "A_PowerPC64": {-                                "FreeBSD": {-                                    "( < 1.5.1 && == 1.5.2 && <= 3.2.1 ) || ( >= 2.1.4 && >= 3.3.1 && <= 2.4.3 && < 4.2.4 && <= 4.4.1 )": {-                                        "dlCSize": 1,-                                        "dlHash": "v",-                                        "dlOutput": null,-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "old",-                                            "Nightly",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:hvxbbv"-                                    },-                                    "( < 4.3.4 && > 5.5.5 && < 2.3.3 )": {-                                        "dlCSize": -7,-                                        "dlHash": "kkkrzee",-                                        "dlOutput": "󱏝\u001e8􀙃浗󺋜_",-                                        "dlSubdir": {-                                            "RegexDir": "󰛐^"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "Nightly",-                                            "Nightly",-                                            "base-4.6.1",-                                            "𐳟M5",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( == 5.3.1 && == 3.6.2 && > 4.2.4 && == 2.3.2 && > 2.3.5 && >= 3.4.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "hxi",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "\u000e;\u001b"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "old",-                                            "\n?a􊎾\u0007",-                                            "Nightly",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:xt"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 6,-                                        "dlHash": "ilho",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "𭺋\u001aq^"-                                        },-                                        "dlTag": [-                                            "Recommended"-                                        ],-                                        "dlUri": "http:"-                                    }-                                },-                                "Windows": {-                                    "( < 3.1.1 && <= 1.2.5 && == 4.1.4 )": {-                                        "dlCSize": 0,-                                        "dlHash": "vtv",-                                        "dlOutput": "袆𣕃MK􎢞",-                                        "dlSubdir": {-                                            "RegexDir": "\u0011.~"-                                        },-                                        "dlTag": [-                                            "Latest",-                                            "Latest",-                                            "Recommended",-                                            "old"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -6,-                                        "dlHash": "",-                                        "dlOutput": "?",-                                        "dlSubdir": {-                                            "RegexDir": "xa"-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:a"-                                    }-                                }-                            },-                            "A_Sparc": {-                                "Darwin": {},-                                "FreeBSD": {-                                    "( < 4.5.3 && >= 5.4.4 && < 4.3.1 && >= 5.4.5 ) || ( == 4.2.1 )": {-                                        "dlCSize": -1,-                                        "dlHash": "s",-                                        "dlOutput": "\u001b",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "http:wvvrvpr"-                                    },-                                    "( <= 5.3.3 && <= 5.1.1 ) || ( < 4.1.1 && < 1.3.2 && < 3.2.4 && > 3.1.1 ) || ( > 1.1.2 ) || ( <= 2.1.2 && >= 2.1.2 && <= 2.2.1 && > 2.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "fpx",-                                        "dlOutput": "#'Ca󿐉󵃍$",-                                        "dlSubdir": {-                                            "RegexDir": "𩔄頍n"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:nefbwq"-                                    },-                                    "( > 1.3.2 && >= 4.2.4 && >= 3.7.4 ) || ( <= 1.2.1 && > 1.3.4 ) || ( > 3.3.3 && == 3.3.3 && < 3.1.3 && <= 1.1.2 ) || ( <= 1.1.2 && <= 1.2.1 && > 2.2.1 ) || ( <= 1.1.1 && > 1.1.1 )": {-                                        "dlCSize": 5,-                                        "dlHash": "vzrgm",-                                        "dlOutput": null,-                                        "dlSubdir": "첌r\u0000^-c",-                                        "dlTag": [-                                            "base-1.3.3",-                                            "old"-                                        ],-                                        "dlUri": "https:et"-                                    },-                                    "( > 2.3.3 ) || ( == 4.1.2 && >= 1.3.2 && < 4.5.4 && >= 1.3.2 ) || ( <= 1.2.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "qmv",-                                        "dlOutput": "",-                                        "dlSubdir": "0Ev6𫥾\u0001",-                                        "dlTag": null,-                                        "dlUri": "http:d"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 7,-                                        "dlHash": "kn",-                                        "dlOutput": "8𡔇U腇",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Experimental",-                                            "LatestPrerelease",-                                            "Latest",-                                            "R)o",-                                            "Latest",-                                            "base-5.2.5",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:e"-                                    }-                                },-                                "Linux_Fedora": {-                                    "( < 2.1.2 && >= 3.1.3 && <= 3.1.3 && <= 1.5.2 && > 1.1.3 && > 3.5.4 && <= 1.4.2 ) || ( < 3.3.4 && == 3.2.1 && < 1.3.3 && == 4.1.1 && == 2.3.3 && < 4.2.3 )": {-                                        "dlCSize": -6,-                                        "dlHash": "lygdwuc",-                                        "dlOutput": "vg󳬂",-                                        "dlSubdir": "LuGXy\u001e",-                                        "dlTag": [-                                            "Latest",-                                            "old",-                                            "",-                                            "base-3.2.2",-                                            "",-                                            "Latest",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:gb"-                                    },-                                    "( < 4.5.5 && > 1.1.5 && == 1.3.4 ) || ( < 1.4.3 && > 3.1.4 ) || ( <= 3.3.3 && == 3.1.2 && >= 3.3.1 && == 4.3.1 ) || ( > 2.2.2 && >= 2.1.2 && == 2.3.2 && <= 2.4.2 )": {-                                        "dlCSize": -2,-                                        "dlHash": "uux",-                                        "dlOutput": "\u001c\u001e.f\u001c ",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Nightly",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:jwhdibc"-                                    },-                                    "( >= 4.2.3 && <= 1.4.5 && <= 6.3.2 && < 2.5.1 )": {-                                        "dlCSize": -5,-                                        "dlHash": "acehtzn",-                                        "dlOutput": "R\u0010\t",-                                        "dlSubdir": "8",-                                        "dlTag": [-                                            "Recommended",-                                            "Nightly",-                                            "Nightly",-                                            "_2䨊;",-                                            "base-5.5.1"-                                        ],-                                        "dlUri": "http:zgmu"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -7,-                                        "dlHash": "sjkk",-                                        "dlOutput": "m-󻧼!",-                                        "dlSubdir": "k󴆇5\u001eD",-                                        "dlTag": null,-                                        "dlUri": "http:kvel"-                                    }-                                },-                                "Windows": {-                                    "( < 5.3.5 && == 3.3.3 )": {-                                        "dlCSize": 7,-                                        "dlHash": "v",-                                        "dlOutput": "I/𠖳􂻻E?\u000f",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:sivsqd"-                                    },-                                    "( <= 4.4.2 && == 5.1.5 && > 2.1.1 && == 4.3.6 && >= 5.5.1 && > 3.4.6 && >= 4.4.3 )": {-                                        "dlCSize": -1,-                                        "dlHash": "frjga",-                                        "dlOutput": ":@𖪗\u000b)Me",-                                        "dlSubdir": "􏳐%\u0016w",-                                        "dlTag": null,-                                        "dlUri": "https:dqdgwn"-                                    },-                                    "( > 5.2.5 && == 2.1.1 && <= 5.3.4 && == 4.3.4 )": {-                                        "dlCSize": 1,-                                        "dlHash": "fi",-                                        "dlOutput": "5\u001e\u0019𩷼]\u001d",-                                        "dlSubdir": {-                                            "RegexDir": "T󷿿\u001f"-                                        },-                                        "dlTag": [-                                            "Recommended"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 2,-                                        "dlHash": "hhtx",-                                        "dlOutput": "p󿍿K",-                                        "dlSubdir": "\u0012\u0004Lj",-                                        "dlTag": [-                                            "Latest",-                                            "old",-                                            "old",-                                            "LatestNightly",-                                            "Prerelease",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:ytfdiib"-                                    }-                                }-                            },-                            "A_Sparc64": {}-                        },-                        "viChangeLog": "http:ncxm",-                        "viPostInstall": null,-                        "viPostRemove": null,-                        "viPreCompile": null,-                        "viPreInstall": "fnek",-                        "viReleaseDay": "-256391684329685-10-18",-                        "viSourceDL": {-                            "dlCSize": -1,-                            "dlHash": "qhl",-                            "dlOutput": "8*I\u0008",-                            "dlSubdir": "",-                            "dlTag": null,-                            "dlUri": "http:dvex"-                        },-                        "viTags": [-                            "Experimental",-                            "Prerelease",-                            "Experimental",-                            "LatestPrerelease"-                        ],-                        "viTestDL": null-                    }-                },-                "Stack": {-                    "4.8.7": {-                        "viArch": {-                            "A_64": {-                                "FreeBSD": {-                                    "( < 2.1.1 && == 5.1.1 && <= 5.1.3 && >= 4.2.4 ) || ( <= 4.2.3 && >= 1.1.3 && <= 4.5.2 && > 2.2.4 ) || ( <= 3.3.1 && == 3.1.1 ) || ( == 1.2.2 && >= 1.2.1 && > 2.2.1 ) || ( < 2.1.1 && < 1.1.1 && <= 2.1.1 )": {-                                        "dlCSize": -7,-                                        "dlHash": "",-                                        "dlOutput": "\u0008𩎹",-                                        "dlSubdir": "󴣅",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Recommended",-                                            "LatestNightly",-                                            "2Go蘱󸩸x",-                                            "old",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:dco"-                                    },-                                    "( < 3.1.4 && == 3.2.3 && <= 3.2.1 )": {-                                        "dlCSize": -3,-                                        "dlHash": "hi",-                                        "dlOutput": "󵿰o<F",-                                        "dlSubdir": "􄉂\u0007",-                                        "dlTag": [-                                            "Prerelease",-                                            "old",-                                            "old"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( == 4.3.3 )": {-                                        "dlCSize": 7,-                                        "dlHash": "",-                                        "dlOutput": ">󺝍nb",-                                        "dlSubdir": "J` ",-                                        "dlTag": null,-                                        "dlUri": "https:sl"-                                    },-                                    "( == 5.4.3 && >= 3.1.4 && > 2.5.5 && > 5.4.3 && < 1.1.6 && <= 2.1.2 )": {-                                        "dlCSize": 7,-                                        "dlHash": "xyue",-                                        "dlOutput": "NM􋰃",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "LatestNightly",-                                            "old",-                                            ">=",-                                            "old"-                                        ],-                                        "dlUri": "https:xsk"-                                    },-                                    "( >= 2.3.2 && <= 2.4.5 && > 1.2.2 ) || ( <= 1.3.1 && >= 1.1.2 && < 3.4.2 ) || ( > 3.2.3 && >= 1.1.2 && > 1.2.1 && < 1.2.2 && == 1.1.1 )": {-                                        "dlCSize": 7,-                                        "dlHash": "b",-                                        "dlOutput": "\u0017\u0019I/ik",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "GmUfb\t"-                                        ],-                                        "dlUri": "https:trdkp"-                                    }-                                },-                                "Windows": {-                                    "( <= 3.3.4 && > 1.4.3 && <= 1.2.3 ) || ( <= 1.3.4 && > 4.2.2 && == 5.1.2 )": {-                                        "dlCSize": 7,-                                        "dlHash": "mvfgogy",-                                        "dlOutput": "mL{\u001dxk",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:uzlhc"-                                    },-                                    "( == 3.5.3 && > 4.2.1 )": {-                                        "dlCSize": 3,-                                        "dlHash": "xhokt",-                                        "dlOutput": null,-                                        "dlSubdir": "",-                                        "dlTag": null,-                                        "dlUri": "https:d"-                                    },-                                    "( > 4.3.3 ) || ( < 1.3.3 && >= 2.1.2 && == 4.3.1 ) || ( < 3.2.2 && <= 3.3.2 && > 2.2.2 && > 3.3.1 && <= 2.1.1 ) || ( <= 1.1.1 && <= 2.1.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "xh",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "cf􌷶Io\u000f"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:adicxvs"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "gnlsysv",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "R="-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "󺁀",-                                            "Latest",-                                            "Latest"-                                        ],-                                        "dlUri": "https:mqxqk"-                                    }-                                }-                            },-                            "A_PowerPC": {},-                            "A_Sparc64": {-                                "FreeBSD": {-                                    "( >= 3.1.3 && <= 5.4.2 && > 3.5.2 && == 3.5.4 && >= 3.5.1 && < 4.5.5 )": {-                                        "dlCSize": -1,-                                        "dlHash": "rmvtvo",-                                        "dlOutput": "gB",-                                        "dlSubdir": "{󹽊\u001bgꏵ𖪡",-                                        "dlTag": [-                                            "Recommended",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:lz"-                                    }-                                },-                                "Linux_Ubuntu": {-                                    "( <= 2.5.5 && < 1.5.2 && <= 3.4.5 ) || ( >= 1.1.3 && > 2.3.4 )": {-                                        "dlCSize": -2,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "",-                                            "LatestPrerelease",-                                            "LatestPrerelease",-                                            "Prerelease",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( <= 3.1.4 && <= 3.2.5 && < 2.4.2 && < 3.1.4 && <= 4.1.3 && <= 4.2.2 && < 4.3.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "qgob",-                                        "dlOutput": "<",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "base-4.1.4",-                                            "base-6.1.6",-                                            "LatestNightly",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:jxondo"-                                    },-                                    "( > 1.2.4 && >= 2.1.5 && < 5.3.5 && > 3.1.3 && == 1.2.5 ) || ( <= 2.4.2 && == 2.3.3 && == 1.4.4 ) || ( <= 2.3.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "f",-                                        "dlOutput": ";",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Latest",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:feny"-                                    },-                                    "( >= 3.1.1 ) || ( < 1.2.3 && <= 3.1.3 && > 4.2.1 )": {-                                        "dlCSize": 4,-                                        "dlHash": "",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "base-3.4.5",-                                            "Nightly",-                                            "LatestPrerelease",-                                            "\u0002𥚖\u0017K\u000f",-                                            "Recommended",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:snq"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 1,-                                        "dlHash": "vykjb",-                                        "dlOutput": "􁳝>\u001e^",-                                        "dlSubdir": ";XY🡨&e",-                                        "dlTag": [-                                            "*SCF",-                                            "Recommended",-                                            "old",-                                            "Prerelease",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:lyeaxz"-                                    }-                                },-                                "Windows": {-                                    "( <= 4.5.3 && < 1.1.2 )": {-                                        "dlCSize": 4,-                                        "dlHash": "vcr",-                                        "dlOutput": ",",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestNightly",-                                            "base-4.4.6",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "( == 3.2.2 && == 5.6.4 && == 2.4.3 && > 4.3.3 )": {-                                        "dlCSize": 3,-                                        "dlHash": "npidtg",-                                        "dlOutput": "%@𰝉\u0004",-                                        "dlSubdir": "Iu{",-                                        "dlTag": null,-                                        "dlUri": "http:bn"-                                    },-                                    "( == 5.5.4 && < 5.3.2 && >= 5.1.4 && < 3.1.5 && <= 4.1.4 && < 5.2.2 ) || ( < 3.3.3 && < 2.2.3 && > 4.2.4 )": {-                                        "dlCSize": -6,-                                        "dlHash": "sjzhx",-                                        "dlOutput": "IP󹧺\u001cL\to",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Recommended",-                                            "Latest",-                                            "",-                                            "Latest",-                                            "Prerelease",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:qfpky"-                                    },-                                    "( > 5.1.1 && < 4.5.5 && < 2.4.3 && < 4.5.1 && <= 5.1.4 )": {-                                        "dlCSize": 5,-                                        "dlHash": "ojqxv",-                                        "dlOutput": "X􏖒􃘸C\u0011",-                                        "dlSubdir": "󲔴󱢤M",-                                        "dlTag": [-                                            "",-                                            "Prerelease",-                                            "LatestPrerelease",-                                            "LatestNightly",-                                            "Latest",-                                            "Recommended",-                                            "Latest"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "( >= 1.2.1 && == 1.2.4 && <= 4.3.4 && == 5.4.5 ) || ( <= 1.2.3 && >= 3.3.4 && >= 1.1.2 && > 2.4.4 && < 1.5.1 && == 1.4.3 )": {-                                        "dlCSize": -2,-                                        "dlHash": "ud",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "LvlM􆳵~"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    }-                                }-                            }-                        },-                        "viChangeLog": "http:j",-                        "viPostInstall": null,-                        "viPostRemove": "bbuy",-                        "viPreCompile": "qowsq",-                        "viPreInstall": "mdxec",-                        "viReleaseDay": "-6647971724430441-01-30",-                        "viSourceDL": {-                            "dlCSize": 2,-                            "dlHash": "hq",-                            "dlOutput": "𡳼",-                            "dlSubdir": {-                                "RegexDir": "d==)"-                            },-                            "dlTag": [-                                "Recommended",-                                "Prerelease",-                                "LatestPrerelease",-                                "base-1.4.4",-                                "Recommended"-                            ],-                            "dlUri": "https:hs"-                        },-                        "viTags": [-                            "\t",-                            "Recommended",-                            "Prerelease",-                            "Latest",-                            "LatestPrerelease",-                            "old"-                        ],-                        "viTestDL": null-                    }-                }-            },-            "metadataUpdate": "http:zvc",-            "toolRequirements": {-                "GHC": {-                    "3.4.5": {-                        "Darwin": {-                            "( < 3.4.1 && == 4.5.5 && <= 1.5.3 && < 3.1.1 && == 2.2.3 )": {-                                "distroPKGs": [],-                                "notes": "ph"-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "",-                                    "pdfux",-                                    "zvff",-                                    ""-                                ],-                                "notes": "gwi"-                            }-                        },-                        "FreeBSD": {-                            "( == 3.4.2 && > 1.5.5 ) || ( >= 3.4.2 && < 4.4.4 && == 4.3.3 )": {-                                "distroPKGs": [-                                    "caqunn",-                                    "cczphyq",-                                    "",-                                    "aedkf",-                                    "ndbfp"-                                ],-                                "notes": "qtru"-                            },-                            "( > 3.2.1 && == 5.4.5 && > 1.5.5 && <= 1.3.3 && >= 1.6.3 && < 1.3.5 )": {-                                "distroPKGs": [-                                    ""-                                ],-                                "notes": "fntfd"-                            },-                            "( >= 2.1.2 && >= 1.1.5 && < 4.2.5 && > 2.3.2 && > 2.1.3 && > 2.5.2 && <= 5.3.1 ) || ( < 2.3.2 && <= 4.3.4 && == 1.4.4 && >= 4.4.3 && <= 4.4.2 && > 4.2.1 ) || ( == 1.4.3 && >= 1.4.3 && == 3.3.3 && > 3.1.3 && > 2.4.3 )": {-                                "distroPKGs": [],-                                "notes": "jiu"-                            },-                            "( >= 3.5.3 && < 4.3.4 && <= 3.5.2 && > 3.4.1 && <= 5.1.1 )": {-                                "distroPKGs": [-                                    "jcpyqj",-                                    "ryytz",-                                    "q",-                                    "",-                                    "pcdb",-                                    "ev",-                                    "gzt"-                                ],-                                "notes": "iom"-                            }-                        },-                        "Windows": {-                            "( == 1.2.2 && < 4.4.2 && >= 1.1.3 && >= 5.2.5 ) || ( >= 3.2.3 && >= 2.1.1 && <= 1.4.2 && <= 2.2.1 ) || ( <= 1.4.3 && > 3.2.2 && == 1.1.2 ) || ( >= 3.1.1 && < 1.2.1 && > 2.1.2 && == 2.2.1 ) || ( < 1.1.2 && >= 1.1.1 ) || ( >= 1.1.3 && == 1.1.1 )": {-                                "distroPKGs": [-                                    "gmsu"-                                ],-                                "notes": "ktadh"-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "dhbn",-                                    "nbin"-                                ],-                                "notes": "f"-                            }-                        }-                    },-                    "5.4.8": {-                        "Darwin": {-                            "( < 3.2.5 && >= 2.5.1 && <= 1.5.1 )": {-                                "distroPKGs": [],-                                "notes": "znb"-                            },-                            "( < 3.5.4 && > 1.3.4 && >= 4.4.1 ) || ( > 1.4.2 && < 3.1.4 && >= 4.1.4 ) || ( <= 3.2.1 ) || ( < 2.2.2 )": {-                                "distroPKGs": [-                                    "macgaby"-                                ],-                                "notes": "ksdjzd"-                            },-                            "( <= 2.1.4 && <= 1.3.4 && > 1.1.4 && < 1.2.2 )": {-                                "distroPKGs": [-                                    "on",-                                    "iqjsmbg",-                                    "brdrruo",-                                    "ei"-                                ],-                                "notes": "scvt"-                            },-                            "( <= 2.2.6 )": {-                                "distroPKGs": [-                                    "",-                                    "fp",-                                    "ldhib",-                                    "",-                                    "kpr"-                                ],-                                "notes": "gk"-                            },-                            "( <= 3.3.5 && < 4.4.6 && < 4.3.5 && > 5.1.4 ) || ( == 4.1.2 && <= 2.3.3 && >= 4.1.3 )": {-                                "distroPKGs": [],-                                "notes": "hmub"-                            },-                            "( > 1.4.1 && > 3.3.2 && <= 3.2.5 && >= 2.1.5 && <= 2.3.1 && == 2.6.3 && < 5.1.1 )": {-                                "distroPKGs": [-                                    "lhvam",-                                    "teunnf",-                                    "d",-                                    "af",-                                    "h",-                                    "frpv",-                                    "qowqj"-                                ],-                                "notes": "iynkj"-                            },-                            "( >= 1.2.3 && > 4.3.3 && < 3.2.2 && <= 1.5.2 && <= 4.2.3 && < 5.5.3 && == 4.1.4 )": {-                                "distroPKGs": [-                                    "lcn",-                                    "mbhytud",-                                    "xpqjr",-                                    "",-                                    "llh",-                                    "dw"-                                ],-                                "notes": "rxusfr"-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "rpmx"-                                ],-                                "notes": "lwserqs"-                            }-                        },-                        "Windows": {}-                    }-                },-                "Stack": {-                    "1.8.6": {-                        "Darwin": {-                            "( < 3.4.1 && <= 5.5.3 && <= 2.4.5 && >= 2.2.1 )": {-                                "distroPKGs": [-                                    "fsj",-                                    "y",-                                    "whhz",-                                    "gxblcii",-                                    "shsbjfx"-                                ],-                                "notes": "htuc"-                            },-                            "( <= 1.3.4 && == 4.3.5 && <= 2.3.5 && > 1.5.3 && > 4.4.4 ) || ( >= 1.2.1 && >= 4.3.4 && == 1.3.1 && <= 3.2.4 && < 3.1.1 )": {-                                "distroPKGs": [-                                    "",-                                    "ty",-                                    "h",-                                    "",-                                    "bkio"-                                ],-                                "notes": "kgr"-                            },-                            "( <= 3.3.1 && < 2.2.4 && <= 2.1.1 && == 3.1.1 && > 5.1.5 ) || ( > 4.3.3 && < 3.4.2 && == 4.1.1 && <= 3.1.2 )": {-                                "distroPKGs": [-                                    "faeoz",-                                    "qzzhkf",-                                    "i",-                                    "ex",-                                    "mawj"-                                ],-                                "notes": "bcj"-                            },-                            "( <= 5.1.5 && == 4.4.4 ) || ( < 4.2.1 && >= 3.3.1 && >= 1.2.1 && < 1.1.3 && > 3.2.3 && <= 1.1.1 ) || ( == 1.3.2 && <= 1.1.3 && < 3.1.3 && > 1.3.2 ) || ( >= 2.1.1 )": {-                                "distroPKGs": [-                                    "bj",-                                    "tgzoh",-                                    "ilmasub",-                                    "u",-                                    "tyxyhfs"-                                ],-                                "notes": "ohulzi"-                            },-                            "( == 1.4.4 && > 2.4.4 )": {-                                "distroPKGs": [-                                    "xbgef",-                                    "nxxdq",-                                    "twlxgj",-                                    "vv",-                                    "cgain",-                                    "ethdy",-                                    "vuzt"-                                ],-                                "notes": "vqr"-                            },-                            "( > 2.1.3 && < 4.1.3 && <= 2.4.1 )": {-                                "distroPKGs": [-                                    "upvuff",-                                    "u",-                                    "nsmeerw"-                                ],-                                "notes": ""-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "",-                                    "m",-                                    "zocyf",-                                    "",-                                    "si",-                                    ""-                                ],-                                "notes": "wsa"-                            }-                        },-                        "FreeBSD": {-                            "( < 4.1.5 && <= 3.4.4 && <= 4.4.4 && > 2.4.5 ) || ( >= 3.1.3 && <= 2.3.3 && == 2.2.1 && == 2.2.4 )": {-                                "distroPKGs": [-                                    "bvchlp",-                                    "i",-                                    "",-                                    "csooqg",-                                    "yslp"-                                ],-                                "notes": "dd"-                            },-                            "( < 4.5.4 && < 1.1.3 && >= 5.4.5 && > 3.1.2 && > 2.5.3 && >= 2.4.1 && < 2.5.1 )": {-                                "distroPKGs": [-                                    "ppqqris",-                                    "qrhr"-                                ],-                                "notes": ""-                            },-                            "( > 1.3.1 && == 2.5.3 && > 4.1.5 && >= 5.2.2 ) || ( > 3.1.3 && > 1.1.4 && < 4.5.2 && < 2.2.3 && < 3.1.2 && > 3.2.3 ) || ( <= 1.1.2 && < 3.1.1 && == 2.1.3 ) || ( > 1.1.2 && < 1.2.1 && >= 2.2.2 ) || ( >= 1.1.1 ) || ( >= 1.2.1 )": {-                                "distroPKGs": [-                                    "vmperqw",-                                    "lztlsbd"-                                ],-                                "notes": "rgglhhw"-                            },-                            "( > 2.2.1 && >= 3.4.3 && > 3.5.4 && > 4.2.2 ) || ( < 3.2.2 && < 3.2.2 && == 3.2.4 && <= 2.2.1 )": {-                                "distroPKGs": [-                                    "jio",-                                    "cot",-                                    "bd"-                                ],-                                "notes": "chcg"-                            },-                            "( > 5.1.3 && >= 2.2.1 && == 6.2.5 && <= 4.3.2 && < 5.4.2 ) || ( > 1.4.4 ) || ( == 2.3.1 && > 2.2.1 && >= 2.3.3 && == 1.1.2 && >= 2.1.2 )": {-                                "distroPKGs": [-                                    "zgvmkz",-                                    "dqzh",-                                    "maiheoh"-                                ],-                                "notes": ""-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "swc",-                                    "nvhy",-                                    "xkwrm",-                                    "fgkbg",-                                    "sed",-                                    "xlgkeu"-                                ],-                                "notes": "dz"-                            }-                        },-                        "Linux_UnknownLinux": {-                            "( < 3.5.5 && <= 2.3.2 && < 4.1.2 && < 5.5.3 && > 3.2.5 && > 3.5.1 )": {-                                "distroPKGs": [-                                    "",-                                    ""-                                ],-                                "notes": "a"-                            },-                            "( == 3.1.5 )": {-                                "distroPKGs": [-                                    "dylcx",-                                    "wdypfjw",-                                    "nm"-                                ],-                                "notes": ""-                            },-                            "( == 5.3.1 && < 2.2.4 && == 5.1.3 && <= 3.4.4 && < 5.2.2 && <= 2.4.4 && > 1.4.5 ) || ( < 2.1.4 && == 1.4.3 && == 3.1.1 ) || ( > 1.1.2 && > 1.3.3 && == 4.3.2 && <= 2.2.2 && > 5.2.1 ) || ( < 1.1.2 && < 2.1.1 && == 1.2.2 && <= 1.2.1 )": {-                                "distroPKGs": [-                                    "ju",-                                    "eisimx",-                                    "flpigjs",-                                    "bhezmsj"-                                ],-                                "notes": "jxf"-                            }-                        },-                        "Windows": {-                            "( < 2.3.4 && > 5.4.6 && <= 2.2.1 && > 4.2.2 )": {-                                "distroPKGs": [-                                    "ier",-                                    "",-                                    "xueyka",-                                    "",-                                    "xjzhzmn"-                                ],-                                "notes": "zpb"-                            },-                            "( == 2.3.1 ) || ( >= 4.1.3 && > 1.3.4 ) || ( > 3.1.3 )": {-                                "distroPKGs": [-                                    "hbebzn",-                                    "y",-                                    "",-                                    "shchzbq"-                                ],-                                "notes": "eniidat"-                            },-                            "( >= 1.4.4 && == 1.4.4 && == 4.5.2 && >= 5.1.2 && <= 1.2.1 && < 5.2.2 && <= 1.3.4 )": {-                                "distroPKGs": [-                                    "ceooik",-                                    "kaggxnv",-                                    "kdmi",-                                    "gck",-                                    "b",-                                    "ol",-                                    "joksm"-                                ],-                                "notes": "lmnv"-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "uppiivq"-                                ],-                                "notes": "ckxpx"-                            }-                        }-                    },-                    "2.2.4": {-                        "Windows": {-                            "( >= 4.4.5 && < 5.5.1 && == 2.6.3 && < 1.4.2 && >= 4.1.2 && > 2.1.3 )": {-                                "distroPKGs": [-                                    "kfskuo",-                                    "",-                                    "",-                                    "hm",-                                    "tge",-                                    "dum",-                                    "vrewg"-                                ],-                                "notes": "bhggmup"-                            }-                        }-                    },-                    "2.7.7": {-                        "Darwin": {-                            "( <= 1.2.1 && > 1.5.2 && < 4.2.4 )": {-                                "distroPKGs": [],-                                "notes": "pqfa"-                            },-                            "( <= 1.5.4 && <= 1.4.5 && <= 5.3.2 && > 1.2.2 && == 3.3.4 && >= 4.5.5 && >= 1.5.4 ) || ( > 4.3.2 && == 2.3.4 ) || ( > 1.2.2 ) || ( == 1.1.1 && < 1.2.2 && > 2.1.3 && <= 2.1.1 )": {-                                "distroPKGs": [-                                    "n",-                                    "jcbqi"-                                ],-                                "notes": "yjrncke"-                            },-                            "( == 2.4.3 && == 4.5.3 && > 5.4.1 ) || ( <= 4.2.2 && > 2.3.2 && <= 2.2.4 && >= 3.2.3 && < 3.4.4 && == 2.4.2 )": {-                                "distroPKGs": [-                                    "nzlxc",-                                    "jvfuzgh",-                                    "fxr",-                                    "uylennu",-                                    "",-                                    "oscrxss"-                                ],-                                "notes": ""-                            },-                            "( == 3.5.5 && == 5.2.5 && >= 5.3.1 ) || ( > 2.1.3 && == 4.2.4 && == 1.3.4 && >= 4.2.1 && < 2.2.4 && > 5.1.3 ) || ( == 1.1.1 && >= 3.3.2 && <= 3.2.2 )": {-                                "distroPKGs": [-                                    ""-                                ],-                                "notes": ""-                            },-                            "( >= 1.2.4 && >= 5.2.5 && == 3.2.4 && < 4.5.1 && >= 2.4.1 )": {-                                "distroPKGs": [-                                    "ngpe",-                                    "fyfa",-                                    "",-                                    "ltwdh",-                                    "sey",-                                    "nfudbi",-                                    "ce"-                                ],-                                "notes": "rahac"-                            },-                            "( >= 1.3.5 && <= 3.2.5 && == 6.2.1 && == 4.2.4 && < 2.1.4 )": {-                                "distroPKGs": [-                                    "dyujpe"-                                ],-                                "notes": "vp"-                            },-                            "( >= 5.4.2 && > 1.1.1 && < 5.5.4 && > 2.3.3 && > 5.4.5 && >= 3.5.5 && <= 4.1.5 ) || ( <= 4.4.4 && >= 2.2.3 ) || ( <= 1.2.1 && > 1.1.1 && > 3.3.1 ) || ( > 1.2.1 && == 1.1.2 && > 2.1.1 && < 1.2.3 ) || ( >= 2.1.1 ) || ( == 1.1.1 && < 1.1.1 ) || ( < 1.1.1 ) || ( > 2.2.1 )": {-                                "distroPKGs": [],-                                "notes": "vc"-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "ksptj",-                                    "jkdzak",-                                    "kdrjl",-                                    "mkmuma"-                                ],-                                "notes": "rhppkld"-                            }-                        },-                        "FreeBSD": {-                            "( <= 3.4.5 && <= 2.2.3 && == 3.2.3 ) || ( >= 2.1.1 ) || ( <= 1.3.2 && < 3.1.2 ) || ( >= 1.2.1 && <= 2.1.2 && > 2.2.1 ) || ( <= 1.1.1 && < 1.1.1 && < 1.1.1 ) || ( >= 2.1.2 ) || ( < 1.1.1 ) || ( < 1.1.2 )": {-                                "distroPKGs": [-                                    "vzntgvh"-                                ],-                                "notes": "fhugvz"-                            },-                            "( <= 5.1.4 )": {-                                "distroPKGs": [-                                    "b",-                                    "tpw",-                                    "unlvn",-                                    "wojkac",-                                    "dal",-                                    "mhofh",-                                    "kv"-                                ],-                                "notes": "t"-                            },-                            "( == 5.3.4 && > 3.5.1 && > 2.5.5 ) || ( == 1.3.4 && <= 2.4.3 ) || ( == 1.1.2 && > 1.3.1 && > 2.2.1 && > 3.1.2 && >= 2.1.3 )": {-                                "distroPKGs": [-                                    "jbk",-                                    "aavt",-                                    "ke",-                                    "a"-                                ],-                                "notes": "thhhyv"-                            },-                            "( > 1.1.1 && <= 5.5.2 && <= 3.4.4 && <= 4.4.1 && == 4.5.5 && < 3.3.4 )": {-                                "distroPKGs": [],-                                "notes": "bd"-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "inzh"-                                ],-                                "notes": ""-                            }-                        },-                        "Linux_AmazonLinux": {-                            "( <= 5.1.3 && >= 3.2.5 && <= 3.1.5 && >= 3.1.3 && <= 1.1.5 && == 4.2.3 && == 1.4.1 ) || ( == 2.3.4 && < 4.1.1 ) || ( == 2.2.3 && < 1.3.2 )": {-                                "distroPKGs": [-                                    "qckpqv",-                                    "figgk",-                                    ""-                                ],-                                "notes": "hxpoh"-                            }-                        },-                        "Linux_Gentoo": {-                            "( <= 3.4.1 && == 5.4.4 && > 2.1.5 && <= 5.5.3 && <= 5.5.4 && <= 3.1.1 && == 4.4.4 ) || ( <= 5.2.4 && >= 2.6.4 ) || ( <= 3.4.1 && < 3.3.3 )": {-                                "distroPKGs": [-                                    "plc",-                                    "lnuqwb",-                                    ""-                                ],-                                "notes": "s"-                            },-                            "( == 4.5.5 && <= 6.5.1 && >= 4.3.4 && > 4.2.4 )": {-                                "distroPKGs": [],-                                "notes": "yiudh"-                            },-                            "( >= 4.3.4 && == 4.3.2 )": {-                                "distroPKGs": [-                                    "d",-                                    "rqcd",-                                    "",-                                    "bdcwwrl",-                                    "",-                                    "zfhrnx"-                                ],-                                "notes": ""-                            },-                            "( >= 5.5.2 && >= 1.4.4 && <= 5.5.4 && < 4.1.2 && < 3.3.1 && < 5.2.1 && <= 1.2.5 )": {-                                "distroPKGs": [-                                    "f"-                                ],-                                "notes": "zwmwgeh"-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "biekdt",-                                    "o"-                                ],-                                "notes": "re"-                            }-                        }-                    },-                    "6.8.4": {-                        "FreeBSD": {-                            "( == 1.4.5 && <= 1.1.2 && >= 4.2.1 && >= 1.1.5 )": {-                                "distroPKGs": [-                                    "",-                                    "g",-                                    "pwtydn",-                                    ""-                                ],-                                "notes": "po"-                            },-                            "( == 5.3.5 && >= 5.2.3 && <= 1.1.4 && <= 1.3.1 ) || ( > 1.4.3 && >= 2.3.2 && == 4.3.3 && == 4.1.2 && > 1.1.4 && <= 2.2.2 )": {-                                "distroPKGs": [-                                    "",-                                    "l",-                                    "xjhxvzn",-                                    "qs",-                                    "sask"-                                ],-                                "notes": "aogkrwa"-                            },-                            "( > 1.2.1 && == 4.1.4 && == 5.2.1 && >= 1.5.2 && >= 2.5.4 && >= 2.5.5 )": {-                                "distroPKGs": [-                                    "",-                                    "lqrbg",-                                    "s",-                                    "",-                                    "otu"-                                ],-                                "notes": "tosd"-                            },-                            "( >= 2.3.4 && > 3.4.1 && > 1.3.2 && <= 1.1.3 ) || ( >= 4.2.1 && < 3.2.1 && < 1.2.3 && < 1.2.2 && >= 2.1.3 && > 3.3.4 )": {-                                "distroPKGs": [-                                    "faivjh",-                                    "",-                                    "xxdmsa"-                                ],-                                "notes": "qt"-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "ckvtmvi",-                                    "xkezz",-                                    "xdfthx",-                                    "eucoqa",-                                    "zppeszt",-                                    "ojgto",-                                    "x"-                                ],-                                "notes": "i"-                            }-                        },-                        "Windows": {-                            "( < 2.3.5 && == 5.3.2 && <= 4.1.4 && == 5.3.4 && > 4.3.4 && <= 2.3.3 ) || ( == 4.3.3 ) || ( == 1.1.3 && >= 2.1.1 && > 1.2.2 && > 1.2.2 && <= 2.3.2 )": {-                                "distroPKGs": [-                                    "i",-                                    "",-                                    "pbbmalu",-                                    "odhxpfl",-                                    "ywmop",-                                    "wjl",-                                    "qn"-                                ],-                                "notes": "gl"-                            },-                            "( < 5.2.4 ) || ( <= 5.1.4 && <= 3.1.2 )": {-                                "distroPKGs": [-                                    "rxb",-                                    "dr",-                                    "u",-                                    "ztrvua",-                                    "pvw"-                                ],-                                "notes": "gfy"-                            },-                            "( <= 5.4.2 && > 1.4.4 && > 3.1.1 && == 3.5.2 && < 1.5.3 && < 6.4.2 ) || ( < 1.2.3 && >= 4.3.1 && >= 2.1.4 ) || ( <= 1.3.2 && >= 2.1.3 && > 3.1.2 && > 3.3.1 && < 2.1.2 ) || ( >= 1.4.1 && > 1.1.2 )": {-                                "distroPKGs": [],-                                "notes": "zfi"-                            },-                            "( == 2.2.1 )": {-                                "distroPKGs": [-                                    "dthpvq",-                                    "skwf",-                                    "xqeqmrp",-                                    "q",-                                    "avdone",-                                    "gb"-                                ],-                                "notes": ""-                            },-                            "( > 1.3.4 && <= 3.2.2 && > 4.2.3 && < 4.3.2 && == 5.2.1 && <= 3.6.1 && >= 2.4.4 ) || ( <= 5.2.3 && > 3.1.2 && <= 4.2.1 && > 5.4.1 )": {-                                "distroPKGs": [-                                    "mzdntj",-                                    "vjjqxn",-                                    "lzi",-                                    "rjfwyom",-                                    "eot",-                                    "v",-                                    "uyudpj"-                                ],-                                "notes": "tiusdgl"-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "zf",-                                    "nwx",-                                    "g",-                                    "gknaeoj",-                                    "",-                                    "ravwwgq",-                                    "lgvau"-                                ],-                                "notes": "vwrra"-                            }-                        }-                    },-                    "8.3.2": {-                        "FreeBSD": {-                            "( < 4.1.2 && >= 5.1.1 ) || ( > 1.3.2 && >= 1.4.3 && <= 1.2.4 && < 4.3.1 )": {-                                "distroPKGs": [-                                    "iwn",-                                    "l",-                                    "dwz"-                                ],-                                "notes": "gbeadc"-                            },-                            "( > 1.2.1 && >= 3.4.4 && >= 3.3.1 && < 5.1.3 && < 3.6.5 && >= 2.5.4 )": {-                                "distroPKGs": [],-                                "notes": "tb"-                            },-                            "( > 1.5.2 && == 3.3.2 && <= 2.5.4 && > 3.3.3 && >= 1.2.5 && <= 2.3.4 && <= 4.1.2 ) || ( >= 2.4.5 && < 4.4.3 && < 2.4.2 && > 3.1.4 ) || ( >= 3.1.2 && == 3.1.1 && <= 3.1.3 && == 1.2.1 )": {-                                "distroPKGs": [],-                                "notes": "lqb"-                            },-                            "( > 4.4.3 && < 2.2.4 && < 2.3.5 && >= 1.3.6 && >= 5.1.1 && >= 4.3.3 ) || ( <= 3.3.2 && > 3.2.2 )": {-                                "distroPKGs": [-                                    "egzfx",-                                    "ix",-                                    "xmkhxqy",-                                    "ize"-                                ],-                                "notes": "mfooe"-                            },-                            "( > 4.4.5 && == 5.3.5 && < 1.5.4 && > 4.3.2 && > 2.5.1 && == 1.4.4 ) || ( == 2.1.1 && > 1.1.4 && > 5.4.1 && == 2.4.4 && > 2.4.2 )": {-                                "distroPKGs": [-                                    "oacvwt"-                                ],-                                "notes": "jbrq"-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "f"-                                ],-                                "notes": "po"-                            }-                        },-                        "Linux_Debian": {-                            "( <= 1.3.2 && == 2.4.4 && >= 4.1.4 && <= 2.3.5 )": {-                                "distroPKGs": [-                                    "bpojqn",-                                    "srm"-                                ],-                                "notes": "hgbnf"-                            }-                        },-                        "Windows": {-                            "( < 3.1.3 && == 2.2.5 && < 4.2.4 && < 4.4.2 )": {-                                "distroPKGs": [-                                    "wpf",-                                    "stvws",-                                    "fsnc",-                                    "qcdpf",-                                    "",-                                    "tzgg"-                                ],-                                "notes": ""-                            },-                            "( == 2.3.4 && <= 5.3.4 && >= 3.1.3 && <= 2.2.5 && <= 1.1.5 && >= 5.5.1 && < 3.5.2 ) || ( > 3.1.1 )": {-                                "distroPKGs": [-                                    "ihicfkk",-                                    "vnhpar",-                                    "blpfb",-                                    "fjxzr"-                                ],-                                "notes": "tgjadwo"-                            },-                            "( > 3.5.3 && == 1.1.5 && > 2.1.4 && > 4.2.1 ) || ( < 3.3.4 && == 3.4.2 && < 1.2.4 && < 4.2.3 && <= 4.4.3 ) || ( > 3.3.2 && > 1.3.4 && >= 2.1.1 ) || ( == 1.3.2 && > 2.2.2 && >= 1.2.2 )": {-                                "distroPKGs": [-                                    "h",-                                    "iychqh"-                                ],-                                "notes": "bugbgk"-                            },-                            "( >= 2.2.3 && < 5.2.1 && < 5.3.5 && == 1.3.2 && >= 4.4.1 && == 3.4.3 )": {-                                "distroPKGs": [-                                    "oiw",-                                    "w",-                                    "x",-                                    "hvcczcx",-                                    "mysrab",-                                    "rsrcq",-                                    "ze"-                                ],-                                "notes": ""-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "",-                                    "ib",-                                    "c",-                                    "ro",-                                    "twuuqzm",-                                    "vjndhwg"-                                ],-                                "notes": "wxehuaj"-                            }-                        }-                    },-                    "unknown_version": {-                        "FreeBSD": {-                            "( < 3.3.3 )": {-                                "distroPKGs": [],-                                "notes": ""-                            },-                            "( == 3.2.4 && > 5.4.3 && == 5.5.2 && > 1.2.5 && <= 4.4.3 )": {-                                "distroPKGs": [-                                    "u",-                                    "c",-                                    "foqv",-                                    "pupmk",-                                    "cru",-                                    "",-                                    "yhldf"-                                ],-                                "notes": "uoecga"-                            },-                            "( == 4.5.4 && >= 3.2.4 && == 5.5.1 && <= 2.1.2 && < 1.4.2 && >= 4.1.5 )": {-                                "distroPKGs": [-                                    "qowkmjz",-                                    ""-                                ],-                                "notes": "q"-                            },-                            "( > 3.2.2 && > 1.3.2 && < 2.5.5 && > 4.3.1 && == 5.4.2 && > 5.5.5 && == 1.1.5 )": {-                                "distroPKGs": [-                                    "yiqut",-                                    "kcau",-                                    "",-                                    "cfe",-                                    "nlwwcf"-                                ],-                                "notes": "rur"-                            },-                            "( >= 2.5.2 ) || ( >= 4.3.1 && <= 1.2.2 && > 2.4.3 && >= 4.3.2 && >= 1.2.1 )": {-                                "distroPKGs": [-                                    "cgnj",-                                    "",-                                    "ztz",-                                    "qp"-                                ],-                                "notes": "qzke"-                            },-                            "( >= 4.5.5 && > 2.1.1 && == 5.1.1 && >= 2.4.4 && == 4.3.1 )": {-                                "distroPKGs": [-                                    "gis"-                                ],-                                "notes": "okgdges"-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "ycgh"-                                ],-                                "notes": "lazve"-                            }-                        },-                        "Linux_Mint": {}-                    }-                }-            }-        },-        {-            "ghcupDownloads": {-                "GHCup": {-                    "3.7.8": {-                        "viArch": {},-                        "viChangeLog": "https:uva",-                        "viPostInstall": "hzfgsq",-                        "viPostRemove": "wnwug",-                        "viPreCompile": "npb",-                        "viPreInstall": "kbrplks",-                        "viReleaseDay": null,-                        "viSourceDL": null,-                        "viTags": [],-                        "viTestDL": {-                            "dlCSize": 5,-                            "dlHash": "l",-                            "dlOutput": null,-                            "dlSubdir": {-                                "RegexDir": "hD@"-                            },-                            "dlTag": null,-                            "dlUri": "http:t"-                        }-                    },-                    "5.8.8": {-                        "viArch": {-                            "A_64": {},-                            "A_PowerPC": {-                                "FreeBSD": {-                                    "( >= 1.4.4 && >= 1.5.5 ) || ( < 1.2.1 ) || ( <= 2.1.1 && > 1.1.2 && >= 2.3.2 )": {-                                        "dlCSize": -4,-                                        "dlHash": "uxek",-                                        "dlOutput": "󷅿󿟃\u000e𘰈",-                                        "dlSubdir": "𬦴󲢾<Hn\u000f",-                                        "dlTag": [],-                                        "dlUri": "http:l"-                                    },-                                    "( >= 3.3.1 && >= 1.6.4 && >= 3.2.2 && > 2.3.5 && == 1.1.4 && < 2.4.3 && >= 1.2.4 )": {-                                        "dlCSize": 2,-                                        "dlHash": "mggd",-                                        "dlOutput": "k[Y",-                                        "dlSubdir": "][PY",-                                        "dlTag": [-                                            "",-                                            "base-3.2.3"-                                        ],-                                        "dlUri": "https:f"-                                    },-                                    "( >= 5.5.5 && > 1.1.2 ) || ( >= 2.4.1 && >= 4.2.2 && >= 3.4.4 ) || ( == 2.4.2 )": {-                                        "dlCSize": 7,-                                        "dlHash": "tuuoft",-                                        "dlOutput": "𖢱\u000b",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:rua"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -7,-                                        "dlHash": "kbkkp",-                                        "dlOutput": "^u􅺕",-                                        "dlSubdir": {-                                            "RegexDir": "\r^𣣠P􍎬"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "Experimental",-                                            "old",-                                            "LatestPrerelease",-                                            "Recommended",-                                            "Nightly",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:gt"-                                    }-                                },-                                "Linux_Gentoo": {-                                    "( <= 5.1.3 && <= 3.1.2 && <= 3.5.2 && == 4.5.1 ) || ( > 2.3.4 && <= 3.2.4 && == 1.2.4 && > 5.2.5 && <= 2.2.2 ) || ( == 3.1.1 && < 3.1.1 && < 2.1.2 && == 2.1.3 )": {-                                        "dlCSize": 7,-                                        "dlHash": "czntg",-                                        "dlOutput": "1I`",-                                        "dlSubdir": {-                                            "RegexDir": "`\r\u001f"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:mvnxy"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 1,-                                        "dlHash": "tmiw",-                                        "dlOutput": "\u001ec",-                                        "dlSubdir": {-                                            "RegexDir": "𬪙3"-                                        },-                                        "dlTag": [-                                            "base-3.5.2",-                                            "Ot~U\u001a\n",-                                            "\u001d睹𮜐J3",-                                            "Nightly",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:jd"-                                    }-                                },-                                "Linux_OpenSUSE": {-                                    "( < 2.5.2 ) || ( < 2.4.2 && >= 2.4.4 && <= 4.1.1 && > 4.1.3 && < 2.4.3 && <= 1.2.4 ) || ( < 3.1.1 && > 3.2.4 && < 3.3.3 && <= 3.2.2 && >= 2.2.1 )": {-                                        "dlCSize": 4,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Recommended",-                                            "Recommended",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:y"-                                    },-                                    "( < 5.3.5 && <= 3.4.1 && >= 2.3.4 && <= 1.5.1 && <= 2.1.2 && <= 3.5.3 ) || ( > 1.4.1 && >= 1.3.4 && <= 3.1.4 && == 1.2.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "ooztaj",-                                        "dlOutput": "=",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Latest"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( > 2.2.5 && == 1.4.3 )": {-                                        "dlCSize": -4,-                                        "dlHash": "jv",-                                        "dlOutput": null,-                                        "dlSubdir": "􎣖|",-                                        "dlTag": [-                                            "Nightly"-                                        ],-                                        "dlUri": "http:mq"-                                    },-                                    "( > 2.4.3 && == 2.1.5 && <= 3.2.4 && < 4.5.4 && < 1.4.5 && < 2.5.4 && < 2.4.5 ) || ( < 1.2.3 && >= 2.1.2 ) || ( == 1.1.2 && >= 4.3.1 && < 1.1.1 && <= 2.2.2 ) || ( >= 3.1.2 )": {-                                        "dlCSize": 3,-                                        "dlHash": "xmgzvi",-                                        "dlOutput": "\u0005i",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "old"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( >= 4.3.2 && == 2.3.5 && <= 4.6.1 && < 2.1.1 )": {-                                        "dlCSize": -6,-                                        "dlHash": "kvcgpw",-                                        "dlOutput": "_|\u0008",-                                        "dlSubdir": {-                                            "RegexDir": "衹iO\u0001\u001c"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:uzq"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -6,-                                        "dlHash": "lxhaj",-                                        "dlOutput": "E",-                                        "dlSubdir": "k;𬽭0􉇒*",-                                        "dlTag": [-                                            "LatestNightly",-                                            "Nightly",-                                            "Latest",-                                            "Recommended",-                                            "LatestNightly",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:"-                                    }-                                }-                            },-                            "A_PowerPC64": {-                                "Darwin": {-                                    "( < 2.4.2 && >= 3.4.4 && == 4.3.1 && == 3.3.1 && == 1.3.4 && <= 1.5.3 && >= 2.3.4 )": {-                                        "dlCSize": 7,-                                        "dlHash": "uhc",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:gkqugi"-                                    },-                                    "( <= 2.3.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "bgyhswo",-                                        "dlOutput": "o4/e􎕀",-                                        "dlSubdir": "󻙡",-                                        "dlTag": [-                                            "LatestNightly",-                                            "Nightly",-                                            "LatestNightly",-                                            "base-5.5.5",-                                            "Recommended",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:hbazg"-                                    },-                                    "( <= 3.3.5 )": {-                                        "dlCSize": 5,-                                        "dlHash": "twhme",-                                        "dlOutput": "",-                                        "dlSubdir": "꠬穞",-                                        "dlTag": null,-                                        "dlUri": "http:hmxeiow"-                                    },-                                    "( > 3.4.1 && > 1.2.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "vvojzxe",-                                        "dlOutput": "󾄝B\u0008KN79",-                                        "dlSubdir": {-                                            "RegexDir": "𬅊􂭕rI"-                                        },-                                        "dlTag": [-                                            "base-6.2.4",-                                            "base-6.5.1"-                                        ],-                                        "dlUri": "https:xsgzs"-                                    },-                                    "( >= 4.5.5 && >= 1.3.4 && <= 5.3.6 && <= 3.3.1 && <= 2.2.3 )": {-                                        "dlCSize": -3,-                                        "dlHash": "",-                                        "dlOutput": "a%",-                                        "dlSubdir": "X􏿴[",-                                        "dlTag": [-                                            "",-                                            "Recommended",-                                            "base-6.6.3",-                                            "Prerelease",-                                            "Latest"-                                        ],-                                        "dlUri": "http:l"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -4,-                                        "dlHash": "etddrj",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "Recommended",-                                            "Nightly",-                                            "Recommended",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:lirlgy"-                                    }-                                },-                                "FreeBSD": {-                                    "( <= 4.3.2 && > 4.1.2 && >= 2.2.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "cbh",-                                        "dlOutput": "gMt",-                                        "dlSubdir": {-                                            "RegexDir": "2w?[t𒂁"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "base-1.7.6",-                                            "old",-                                            "LatestPrerelease",-                                            "Recommended",-                                            "Prerelease",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:bzq"-                                    },-                                    "( == 1.6.3 && <= 1.5.3 && >= 3.2.2 && <= 2.2.2 && > 2.3.4 && < 5.1.5 ) || ( < 4.3.4 && == 1.4.1 && < 4.4.3 ) || ( == 2.3.1 )": {-                                        "dlCSize": -1,-                                        "dlHash": "r",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-2.4.1",-                                            "Nightly",-                                            "old",-                                            "old",-                                            "Nightly",-                                            "Experimental",-                                            "Latest"-                                        ],-                                        "dlUri": "http:rr"-                                    },-                                    "( > 2.2.3 && > 3.6.4 && > 2.5.3 && <= 1.6.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "dksflox",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:gjtgn"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "ax",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:evea"-                                    }-                                },-                                "Windows": {-                                    "( < 2.2.2 && <= 2.4.4 )": {-                                        "dlCSize": 4,-                                        "dlHash": "q",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "Nightly"-                                        ],-                                        "dlUri": "https:zqsvwm"-                                    },-                                    "( == 2.3.3 && < 1.2.4 && >= 5.2.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "rrqxtlo",-                                        "dlOutput": "2𫡾",-                                        "dlSubdir": "g\u000e",-                                        "dlTag": [-                                            "Latest",-                                            "Nightly",-                                            "LatestPrerelease",-                                            "Recommended",-                                            "Experimental",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:iv"-                                    },-                                    "( > 2.2.5 && < 4.2.2 && >= 3.2.5 ) || ( <= 4.4.2 && >= 4.1.3 && == 1.4.3 && >= 3.1.2 && > 1.1.2 && <= 1.2.1 )": {-                                        "dlCSize": 3,-                                        "dlHash": "",-                                        "dlOutput": ".Ts𬼱an􁧤",-                                        "dlSubdir": "𮀏𘄀ỦRr[",-                                        "dlTag": null,-                                        "dlUri": "http:oq"-                                    },-                                    "( > 4.1.3 && == 5.4.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "rdodibe",-                                        "dlOutput": "B\u0003",-                                        "dlSubdir": "",-                                        "dlTag": [],-                                        "dlUri": "http:blvbi"-                                    },-                                    "( >= 4.2.3 && <= 2.3.3 && <= 2.1.3 && < 3.2.2 )": {-                                        "dlCSize": -2,-                                        "dlHash": "alp",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "http:yjbdhl"-                                    }-                                }-                            },-                            "A_Sparc": {}-                        },-                        "viChangeLog": null,-                        "viPostInstall": "zsscc",-                        "viPostRemove": "mqt",-                        "viPreCompile": null,-                        "viPreInstall": null,-                        "viReleaseDay": "-18953436539163570-11-25",-                        "viSourceDL": {-                            "dlCSize": -5,-                            "dlHash": "u",-                            "dlOutput": "t󵀹􇰇",-                            "dlSubdir": "",-                            "dlTag": [-                                "Latest",-                                "Nightly",-                                "base-1.5.5",-                                "Experimental",-                                "!",-                                "Experimental"-                            ],-                            "dlUri": "http:"-                        },-                        "viTags": [-                            "base-7.4.6",-                            "base-2.2.3",-                            "LatestNightly",-                            "q",-                            "base-3.3.5"-                        ],-                        "viTestDL": {-                            "dlCSize": null,-                            "dlHash": "",-                            "dlOutput": "/s(𱠚S\u001d",-                            "dlSubdir": "e",-                            "dlTag": [-                                "Recommended"-                            ],-                            "dlUri": "http:"-                        }-                    }-                },-                "Stack": {-                    "3.8.6": {-                        "viArch": {-                            "A_ARM": {-                                "Darwin": {-                                    "( <= 1.1.3 && == 3.3.4 && > 2.1.1 && <= 4.2.2 )": {-                                        "dlCSize": -1,-                                        "dlHash": "l",-                                        "dlOutput": "𩽘)t+\u0006󼔹",-                                        "dlSubdir": "M|",-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    },-                                    "( <= 2.4.1 && < 2.4.5 && < 1.3.5 && < 4.2.1 && <= 5.4.3 && == 2.3.2 ) || ( == 3.4.3 && <= 3.3.3 && > 4.1.2 && <= 2.3.3 && >= 4.3.2 && == 1.2.2 )": {-                                        "dlCSize": -2,-                                        "dlHash": "hl",-                                        "dlOutput": null,-                                        "dlSubdir": "󳱌G\u0011𪚎􁇴",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Recommended",-                                            "Latest"-                                        ],-                                        "dlUri": "http:trdxyc"-                                    },-                                    "( > 5.4.3 && > 3.4.5 && < 1.4.4 && == 3.1.1 && >= 5.2.4 && == 1.2.2 && == 1.4.1 ) || ( >= 1.2.4 && > 4.1.3 && > 1.2.2 && > 2.1.4 && < 3.4.4 && > 1.2.1 )": {-                                        "dlCSize": 2,-                                        "dlHash": "qds",-                                        "dlOutput": null,-                                        "dlSubdir": "󰶑I",-                                        "dlTag": [-                                            "old",-                                            "LatestPrerelease",-                                            "LatestNightly",-                                            "Prerelease",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:oihov"-                                    },-                                    "( >= 4.4.5 && == 2.2.2 && <= 5.3.4 && >= 2.4.1 && > 5.1.2 && == 1.1.2 && < 2.4.3 )": {-                                        "dlCSize": -2,-                                        "dlHash": "jnjl",-                                        "dlOutput": null,-                                        "dlSubdir": "{i􀖠",-                                        "dlTag": [],-                                        "dlUri": "http:ef"-                                    },-                                    "( >= 5.5.4 && == 3.3.2 ) || ( >= 5.4.1 && <= 3.3.4 && <= 1.3.2 && >= 4.3.4 && <= 3.4.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "nsjf",-                                        "dlOutput": "\u0007Igp",-                                        "dlSubdir": {-                                            "RegexDir": "XO\u001f𥞛\r"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 1,-                                        "dlHash": "e",-                                        "dlOutput": "𣉎#",-                                        "dlSubdir": "~\u0017\\",-                                        "dlTag": [-                                            "Latest",-                                            "Prerelease",-                                            "old",-                                            "LatestNightly",-                                            "Latest"-                                        ],-                                        "dlUri": "https:oorbmyc"-                                    }-                                },-                                "Linux_Alpine": {-                                    "( == 3.1.1 && <= 3.2.2 && <= 2.5.3 && > 2.1.4 && > 1.5.5 && < 3.1.2 && < 2.1.1 ) || ( <= 4.4.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "afsbjo",-                                        "dlOutput": "=\u0010\u0002e\u000eb",-                                        "dlSubdir": "[\u0012C",-                                        "dlTag": [],-                                        "dlUri": "http:bx"-                                    },-                                    "( >= 5.5.3 && <= 4.2.6 && == 3.2.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "rzd",-                                        "dlOutput": "/",-                                        "dlSubdir": "\u0014g𘢟N4&",-                                        "dlTag": null,-                                        "dlUri": "https:qn"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 6,-                                        "dlHash": "uscxvk",-                                        "dlOutput": "󵷯",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:tef"-                                    }-                                }-                            },-                            "A_PowerPC64": {-                                "Darwin": {-                                    "( < 5.1.1 && > 2.4.2 && > 2.1.4 && > 1.4.3 && > 1.1.5 && > 4.5.1 ) || ( <= 1.2.2 && <= 5.4.3 && >= 4.2.4 && > 1.4.1 && <= 2.4.3 ) || ( < 3.1.1 && < 1.3.3 ) || ( >= 2.1.2 && == 2.1.2 && >= 2.2.2 && == 2.1.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "cgbpec",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "?",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:xnzyixz"-                                    },-                                    "( == 2.4.2 && < 2.1.4 && <= 5.5.3 && == 3.1.4 ) || ( > 2.2.4 && > 3.1.4 ) || ( == 3.3.3 && < 1.3.2 && > 3.2.3 && > 2.3.3 )": {-                                        "dlCSize": -3,-                                        "dlHash": "yyu",-                                        "dlOutput": null,-                                        "dlSubdir": "槈𧇌󱈕)^",-                                        "dlTag": null,-                                        "dlUri": "http:m"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "ddqh",-                                        "dlOutput": "󼶵8\u0000",-                                        "dlSubdir": "X􆯾𠝲c\u0007",-                                        "dlTag": [],-                                        "dlUri": "https:o"-                                    }-                                },-                                "FreeBSD": {-                                    "( < 4.5.3 && < 3.1.1 && > 2.4.2 && < 5.4.3 && == 1.4.5 && == 5.2.5 && > 1.2.1 )": {-                                        "dlCSize": -1,-                                        "dlHash": "usdxwul",-                                        "dlOutput": "eUyk􊖣\u0000𢜰",-                                        "dlSubdir": "\u0010󶟰.\u001d\t",-                                        "dlTag": [],-                                        "dlUri": "https:lb"-                                    },-                                    "( < 5.2.3 && <= 5.2.2 && == 3.3.5 ) || ( >= 2.5.4 && < 1.2.4 && <= 1.4.4 )": {-                                        "dlCSize": 1,-                                        "dlHash": "",-                                        "dlOutput": "w",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "https:lokra"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -5,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "4t*"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:xey"-                                    }-                                },-                                "Linux_Rocky": {-                                    "( < 5.4.2 && > 2.5.5 && >= 3.3.5 && >= 5.4.5 && >= 2.3.5 && < 1.5.1 && <= 5.3.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "vy",-                                        "dlOutput": "􂌶",-                                        "dlSubdir": {-                                            "RegexDir": "\u001d*􁸑8e0"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "Latest",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:kjfujg"-                                    },-                                    "( > 5.4.2 && <= 1.4.3 && >= 1.2.4 )": {-                                        "dlCSize": 6,-                                        "dlHash": "kqn",-                                        "dlOutput": "摷\n𱶕",-                                        "dlSubdir": "􂐀\u001c𓐶",-                                        "dlTag": null,-                                        "dlUri": "https:ghjos"-                                    },-                                    "( >= 2.2.1 && < 2.2.1 && < 2.2.6 && >= 5.1.3 && > 3.5.1 ) || ( <= 3.2.4 && < 3.3.1 && == 4.4.3 && >= 4.2.2 )": {-                                        "dlCSize": -1,-                                        "dlHash": "amxjqes",-                                        "dlOutput": "C𦮭𝀷/㱀𨒻\u0017",-                                        "dlSubdir": {-                                            "RegexDir": "OK𬠀U(O"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:xcj"-                                    },-                                    "( >= 3.2.3 && > 2.4.2 && < 3.4.1 && <= 4.2.5 && == 2.1.3 && > 5.3.4 && >= 1.4.4 )": {-                                        "dlCSize": -4,-                                        "dlHash": "jbjtmkl",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "old",-                                            "base-4.1.3"-                                        ],-                                        "dlUri": "https:nvsi"-                                    },-                                    "( >= 5.4.5 && <= 4.3.1 && <= 3.5.5 && < 4.5.4 && > 5.4.1 )": {-                                        "dlCSize": -2,-                                        "dlHash": "er",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "􌤂c󱅣"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:vph"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 0,-                                        "dlHash": "zahhutv",-                                        "dlOutput": "+8",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Recommended",-                                            "Recommended",-                                            "old",-                                            "Nightly",-                                            "LatestPrerelease",-                                            "7\u001a󴹡]N",-                                            "B\u0002!\u0008X\u001f"-                                        ],-                                        "dlUri": "https:qaeyeo"-                                    }-                                }-                            },-                            "A_Sparc": {},-                            "A_Sparc64": {}-                        },-                        "viChangeLog": "http:v",-                        "viPostInstall": null,-                        "viPostRemove": "gnk",-                        "viPreCompile": null,-                        "viPreInstall": "at",-                        "viReleaseDay": "13570284092790869-12-04",-                        "viSourceDL": null,-                        "viTags": [-                            "old",-                            "base-4.5.2",-                            "Nightly",-                            "󹆢Jj%𘏾",-                            "o䳬+g]\u001d"-                        ],-                        "viTestDL": {-                            "dlCSize": -5,-                            "dlHash": "fyt",-                            "dlOutput": "ꋞ7F\u0011O`",-                            "dlSubdir": null,-                            "dlTag": [-                                "LatestPrerelease",-                                "Experimental",-                                "Nightly",-                                "Prerelease"-                            ],-                            "dlUri": "https:xwhzg"-                        }-                    },-                    "6.7.2": {-                        "viArch": {-                            "A_ARM64": {-                                "Darwin": {-                                    "( < 1.2.4 && == 1.3.2 ) || ( < 1.3.4 && < 4.1.4 ) || ( == 1.1.3 && >= 1.3.1 && <= 3.3.2 )": {-                                        "dlCSize": -1,-                                        "dlHash": "y",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "ឹ,\u0010]+"-                                        },-                                        "dlTag": [-                                            "Latest",-                                            "base-4.4.1",-                                            "old",-                                            "Latest",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:qithu"-                                    },-                                    "( == 3.4.2 ) || ( < 2.3.2 && >= 3.3.2 && <= 4.3.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "iuxkgp",-                                        "dlOutput": "\u000e,􃻱h􊪌",-                                        "dlSubdir": "=\u0014",-                                        "dlTag": [-                                            "󼈒k",-                                            "old",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:so"-                                    },-                                    "( > 1.4.4 && <= 3.2.2 && >= 1.2.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "b",-                                        "dlOutput": "",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "Nightly",-                                            "Experimental",-                                            "old",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "( > 4.3.5 && >= 2.5.5 && <= 5.2.1 && > 4.4.2 && <= 1.4.2 && <= 1.5.1 )": {-                                        "dlCSize": 3,-                                        "dlHash": "d",-                                        "dlOutput": "\u0010\u0002\u0006\u0018",-                                        "dlSubdir": {-                                            "RegexDir": "rT\u000f\u0018'"-                                        },-                                        "dlTag": [-                                            "Recommended",-                                            "Prerelease",-                                            "LatestPrerelease",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:obcszq"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "qkwejo",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "%𣀠=􍛏",-                                            "\u000eZ",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:"-                                    }-                                },-                                "FreeBSD": {},-                                "Windows": {-                                    "( <= 2.2.4 && > 2.4.4 && > 3.4.2 && <= 3.3.1 && >= 5.3.4 ) || ( > 3.3.2 && > 2.1.3 && >= 2.3.1 && == 4.4.2 && == 2.3.4 )": {-                                        "dlCSize": -4,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Nightly",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:wdgqit"-                                    },-                                    "( >= 1.1.5 && < 1.3.2 && == 5.5.5 && >= 5.3.5 && >= 3.2.2 && <= 3.2.5 ) || ( > 4.3.4 && <= 5.1.1 )": {-                                        "dlCSize": -3,-                                        "dlHash": "tbiutl",-                                        "dlOutput": "捬",-                                        "dlSubdir": "y\u0007Li",-                                        "dlTag": [-                                            "Nightly",-                                            "Nightly",-                                            "Prerelease",-                                            "Latest"-                                        ],-                                        "dlUri": "https:e"-                                    },-                                    "( >= 5.4.4 && >= 1.3.3 && >= 5.5.5 && >= 2.5.2 && < 2.4.5 && < 2.1.5 ) || ( == 3.2.5 && == 1.4.1 && <= 1.2.1 && == 2.2.3 ) || ( == 2.1.2 && >= 2.1.1 && == 1.3.1 && >= 2.1.1 ) || ( > 1.1.2 && == 2.1.1 && <= 2.1.1 ) || ( == 1.1.1 ) || ( <= 1.1.1 ) || ( == 1.1.1 ) || ( < 1.1.2 )": {-                                        "dlCSize": 5,-                                        "dlHash": "mcerj",-                                        "dlOutput": "\n{\u0006",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "base-5.5.3"-                                        ],-                                        "dlUri": "https:rdooycg"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "jhlzh",-                                        "dlOutput": "𤹙^䄉V8On",-                                        "dlSubdir": {-                                            "RegexDir": "\u0018^"-                                        },-                                        "dlTag": [-                                            "Latest"-                                        ],-                                        "dlUri": "https:"-                                    }-                                }-                            },-                            "A_PowerPC": {-                                "Darwin": {-                                    "( <= 5.5.4 && <= 1.5.1 && <= 5.6.5 && < 1.1.4 )": {-                                        "dlCSize": -2,-                                        "dlHash": "efqy",-                                        "dlOutput": "|",-                                        "dlSubdir": {-                                            "RegexDir": "v𑿙8𭰚"-                                        },-                                        "dlTag": [-                                            "old",-                                            "<",-                                            "Experimental",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:uw"-                                    },-                                    "( == 3.1.5 ) || ( <= 4.5.1 && <= 3.4.2 && == 3.4.3 && >= 4.3.2 && > 4.1.4 ) || ( < 3.3.1 && > 3.1.2 && == 2.1.3 && >= 3.2.1 && < 1.2.4 ) || ( > 2.1.3 && < 1.1.2 && >= 3.1.2 && > 3.2.1 ) || ( >= 2.1.2 )": {-                                        "dlCSize": -1,-                                        "dlHash": "tfkpw",-                                        "dlOutput": "􀔺\"",-                                        "dlSubdir": "졾]H\u001d\\",-                                        "dlTag": [-                                            "old",-                                            "LatestNightly",-                                            "Latest",-                                            "Recommended",-                                            "LatestPrerelease",-                                            "LatestNightly",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:k"-                                    },-                                    "( == 5.1.2 && > 4.3.4 && > 1.3.1 ) || ( > 2.4.4 && == 3.2.3 ) || ( >= 3.3.3 && >= 1.3.1 && >= 2.1.1 && <= 2.1.1 && <= 1.2.1 )": {-                                        "dlCSize": 2,-                                        "dlHash": "ntkw",-                                        "dlOutput": null,-                                        "dlSubdir": "",-                                        "dlTag": null,-                                        "dlUri": "https:xnqrjp"-                                    },-                                    "( >= 1.4.6 && < 2.4.1 )": {-                                        "dlCSize": -1,-                                        "dlHash": "d",-                                        "dlOutput": "t礥`t\u0017",-                                        "dlSubdir": "󺞺p􄫜*觛",-                                        "dlTag": null,-                                        "dlUri": "https:nas"-                                    },-                                    "( >= 3.4.2 && > 3.5.4 )": {-                                        "dlCSize": -5,-                                        "dlHash": "f",-                                        "dlOutput": " F]?3􋱻4",-                                        "dlSubdir": "\u001b",-                                        "dlTag": [-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:pt"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 4,-                                        "dlHash": "ciwojg",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "https:"-                                    }-                                },-                                "FreeBSD": {-                                    "( < 1.1.5 && > 5.2.4 && >= 1.5.5 && < 3.5.4 && < 2.5.2 && >= 3.1.5 ) || ( >= 3.1.2 && > 1.3.3 && > 2.3.2 )": {-                                        "dlCSize": 1,-                                        "dlHash": "",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:eisjkje"-                                    },-                                    "( < 2.1.3 && == 2.5.5 && >= 3.2.2 && == 4.5.3 && < 5.4.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "hkw",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:invidgh"-                                    },-                                    "( <= 1.1.2 && == 3.5.2 && < 5.1.5 && > 5.1.4 && == 1.5.1 && >= 1.3.3 ) || ( == 4.1.2 && < 1.3.2 && >= 1.3.1 ) || ( > 3.1.2 )": {-                                        "dlCSize": -3,-                                        "dlHash": "cxwczma",-                                        "dlOutput": "F𫧙(J!A𰦶",-                                        "dlSubdir": {-                                            "RegexDir": "𧖂𔖓"-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:tserifo"-                                    },-                                    "( == 3.3.2 && > 3.3.3 && >= 5.5.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "so",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Experimental",-                                            "old",-                                            "Recommended",-                                            "base-3.4.3"-                                        ],-                                        "dlUri": "https:qd"-                                    },-                                    "( == 4.4.1 && >= 1.2.4 && >= 5.1.5 && > 1.4.1 && >= 4.4.5 && <= 3.4.1 ) || ( == 4.1.4 && <= 4.3.2 && < 5.4.1 && < 3.4.3 ) || ( > 3.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "pv",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "z=V󿃶"-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "6𧾼\u0012𢪉",-                                            "LatestPrerelease",-                                            "",-                                            "Rm4𦖋>",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:jtmh"-                                    },-                                    "( == 4.5.5 && < 3.2.4 && > 4.1.2 && == 5.3.5 && >= 5.3.1 )": {-                                        "dlCSize": 0,-                                        "dlHash": "",-                                        "dlOutput": "aU\u000c",-                                        "dlSubdir": {-                                            "RegexDir": "T#􈷃\u0016􃘆\u0015"-                                        },-                                        "dlTag": [-                                            "Recommended",-                                            "Recommended",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:jnag"-                                    },-                                    "( >= 5.2.3 && < 3.5.5 && == 4.2.1 && > 1.4.3 && >= 5.4.5 ) || ( >= 4.2.1 && < 1.1.1 )": {-                                        "dlCSize": 7,-                                        "dlHash": "n",-                                        "dlOutput": "@g􃟞)\u001d\u0008#",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "https:hbn"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 3,-                                        "dlHash": "slhuw",-                                        "dlOutput": "\u0016墆",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "LatestNightly",-                                            "Latest"-                                        ],-                                        "dlUri": "http:xohj"-                                    }-                                },-                                "Linux_CentOS": {-                                    "( < 2.1.3 && >= 1.5.1 && <= 2.1.2 && >= 5.4.5 && <= 4.4.4 )": {-                                        "dlCSize": -2,-                                        "dlHash": "khvwiz",-                                        "dlOutput": "\"53𥾆Y+c",-                                        "dlSubdir": "𲎗.C(=!",-                                        "dlTag": null,-                                        "dlUri": "http:mf"-                                    },-                                    "( == 2.2.3 && == 4.2.2 && <= 2.2.3 && > 4.2.1 && < 5.2.4 )": {-                                        "dlCSize": 6,-                                        "dlHash": "pstcjiy",-                                        "dlOutput": "􁘕o\u000e\u000c",-                                        "dlSubdir": "\u001eB\u0008",-                                        "dlTag": null,-                                        "dlUri": "https:kmgff"-                                    },-                                    "( > 1.4.5 && == 3.2.4 && < 4.5.3 && <= 3.5.1 && > 3.4.3 && == 1.2.4 && > 5.1.4 )": {-                                        "dlCSize": 7,-                                        "dlHash": "eto",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Latest",-                                            "Experimental",-                                            "Latest",-                                            "",-                                            "Recommended",-                                            "LatestNightly",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "( > 2.1.2 && <= 4.5.3 && <= 5.1.5 && <= 4.4.1 && == 4.2.4 ) || ( > 2.3.3 && > 2.4.3 && == 2.5.1 && <= 1.2.2 ) || ( >= 1.2.3 )": {-                                        "dlCSize": -3,-                                        "dlHash": "obfw",-                                        "dlOutput": "m㙱𦼱",-                                        "dlSubdir": {-                                            "RegexDir": "w\u0017蹎|"-                                        },-                                        "dlTag": [-                                            "base-4.4.3",-                                            "Nightly",-                                            "Experimental",-                                            "Experimental",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:scthhm"-                                    },-                                    "( >= 5.2.1 && >= 4.5.4 && == 3.5.4 && < 5.1.1 && < 1.5.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "io",-                                        "dlOutput": "󸡉)\u000b􀨜sm4",-                                        "dlSubdir": {-                                            "RegexDir": "󰵞􀈖󳃖\u0013"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "Latest",-                                            "LatestPrerelease",-                                            "Prerelease",-                                            "Nightly",-                                            "old"-                                        ],-                                        "dlUri": "https:kf"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -3,-                                        "dlHash": "cht",-                                        "dlOutput": "+)𗿩\u0017i􎏸᠄",-                                        "dlSubdir": {-                                            "RegexDir": "􌊝뛂}\u0001"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:kema"-                                    }-                                },-                                "Windows": {-                                    "( < 4.5.3 && == 3.2.2 )": {-                                        "dlCSize": -1,-                                        "dlHash": "kcuy",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "@$@~"-                                        },-                                        "dlTag": [-                                            "Nightly"-                                        ],-                                        "dlUri": "https:xtjjqcf"-                                    },-                                    "( > 1.3.2 && <= 2.3.5 && >= 1.5.4 && == 1.2.2 && <= 2.5.3 && < 2.2.2 )": {-                                        "dlCSize": 2,-                                        "dlHash": "o",-                                        "dlOutput": "𭠩\u0006q",-                                        "dlSubdir": "D\u00063\n𰂩\u0007",-                                        "dlTag": [-                                            "Prerelease",-                                            "Latest",-                                            "base-6.2.1",-                                            "Experimental",-                                            "Experimental",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:pnhzoav"-                                    },-                                    "( > 3.2.5 && <= 4.2.5 && == 2.3.3 && > 3.6.5 && > 2.1.1 && >= 1.2.1 ) || ( <= 3.3.1 && < 4.1.3 && <= 4.3.2 && == 4.2.1 && <= 1.1.1 ) || ( > 2.2.2 && < 1.1.3 && < 1.3.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "ygal",-                                        "dlOutput": "X󲩏󳛾n\u0012s󴡵",-                                        "dlSubdir": "",-                                        "dlTag": null,-                                        "dlUri": "https:sevo"-                                    },-                                    "( > 5.1.5 && >= 3.3.4 )": {-                                        "dlCSize": 5,-                                        "dlHash": "xll",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "\t𨕷􃺵"-                                        },-                                        "dlTag": [-                                            "",-                                            "Recommended",-                                            "LatestPrerelease",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:xseoh"-                                    },-                                    "( >= 5.1.1 && < 3.2.4 && >= 3.5.1 && <= 4.4.2 ) || ( <= 4.2.1 && < 3.4.3 && == 5.1.5 && > 3.4.4 )": {-                                        "dlCSize": 5,-                                        "dlHash": "hhcl",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "t"-                                        },-                                        "dlTag": [-                                            "old",-                                            "LatestPrerelease",-                                            "Nightly",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:vmesvgr"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "rzvgcts",-                                        "dlOutput": "Epe0𫄭@L",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Latest"-                                        ],-                                        "dlUri": "http:teojr"-                                    }-                                }-                            },-                            "A_PowerPC64": {-                                "Darwin": {-                                    "( < 4.2.4 ) || ( <= 2.4.4 && < 4.2.4 && < 3.3.5 )": {-                                        "dlCSize": 3,-                                        "dlHash": "hw",-                                        "dlOutput": "\u001c\u001e䟾!s3",-                                        "dlSubdir": {-                                            "RegexDir": ">`ꢓ"-                                        },-                                        "dlTag": [-                                            "Recommended",-                                            "base-3.2.2",-                                            "Recommended",-                                            "Experimental",-                                            "Nightly",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:llewfr"-                                    },-                                    "( <= 4.5.2 && == 4.3.5 && >= 5.4.3 )": {-                                        "dlCSize": 2,-                                        "dlHash": "bz",-                                        "dlOutput": "\u0003;􈫐",-                                        "dlSubdir": {-                                            "RegexDir": "󴍣W𪞳\""-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:"-                                    },-                                    "( > 5.3.5 ) || ( < 1.2.3 && == 4.4.3 && <= 4.3.4 ) || ( <= 3.3.2 && > 3.1.2 && > 2.3.3 ) || ( > 1.2.2 && < 1.2.1 ) || ( >= 1.1.1 ) || ( <= 1.1.1 ) || ( >= 1.1.1 )": {-                                        "dlCSize": 7,-                                        "dlHash": "rmj",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:pnvokmk"-                                    },-                                    "( >= 5.5.5 && > 1.3.3 && <= 1.4.2 && < 1.3.3 && < 4.5.3 ) || ( > 4.3.3 && > 2.1.3 && > 3.3.3 )": {-                                        "dlCSize": 1,-                                        "dlHash": "jwwrt",-                                        "dlOutput": "㞞",-                                        "dlSubdir": "󵪁B\u0012󳬫",-                                        "dlTag": [-                                            "old",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:hrq"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "e",-                                        "dlOutput": "󼩂󷷯^u",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "Nightly"-                                        ],-                                        "dlUri": "http:pa"-                                    }-                                },-                                "FreeBSD": {-                                    "( <= 1.2.2 && < 5.3.2 && <= 4.5.5 && >= 4.5.2 && <= 1.2.4 && > 1.6.1 && > 3.2.6 ) || ( < 2.2.2 && <= 1.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "danwp",-                                        "dlOutput": "+\u0019F_\u000c􋓇s",-                                        "dlSubdir": "S",-                                        "dlTag": null,-                                        "dlUri": "http:hml"-                                    },-                                    "( <= 5.2.1 && < 2.1.1 && >= 3.4.2 && == 5.2.3 && < 5.1.5 && < 5.3.5 ) || ( >= 4.1.4 && == 2.1.4 && < 4.3.4 && == 2.2.2 && == 4.2.1 && == 2.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": "哢XH䕀󶚶G",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-5.6.3",-                                            "old",-                                            "Nightly",-                                            "Nightly",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:ljvuhk"-                                    },-                                    "( == 1.5.2 && < 5.4.1 ) || ( > 1.2.2 && == 1.4.1 && == 1.1.3 && == 2.2.1 && > 3.4.4 ) || ( > 2.1.2 && == 4.2.1 && > 3.3.1 && >= 1.1.3 && >= 2.3.3 ) || ( <= 2.2.3 && > 1.1.2 ) || ( <= 1.1.2 )": {-                                        "dlCSize": 4,-                                        "dlHash": "nrgv",-                                        "dlOutput": "",-                                        "dlSubdir": "𘀕H",-                                        "dlTag": [-                                            "Prerelease",-                                            "LatestPrerelease",-                                            "Prerelease",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "( >= 4.4.3 && <= 4.1.1 && == 2.5.2 && > 4.3.5 && == 4.2.1 && == 2.5.5 && > 5.3.1 ) || ( <= 1.4.3 && <= 3.3.3 && < 4.1.2 && <= 3.1.6 )": {-                                        "dlCSize": null,-                                        "dlHash": "ojyjyb",-                                        "dlOutput": "\u000e\u0002",-                                        "dlSubdir": "\u0013l\u000b𖹾",-                                        "dlTag": [-                                            "",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:qfwe"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 3,-                                        "dlHash": "obctoy",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-5.2.3",-                                            "base-5.3.1",-                                            "Experimental",-                                            "Experimental",-                                            "Nightly",-                                            "Latest",-                                            "old"-                                        ],-                                        "dlUri": "https:nroz"-                                    }-                                },-                                "Windows": {-                                    "( <= 2.1.4 && < 1.3.3 && >= 1.3.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "kwnhae",-                                        "dlOutput": "𨉧aSQ",-                                        "dlSubdir": "\u0007`7𫓏e􇠬",-                                        "dlTag": null,-                                        "dlUri": "http:u"-                                    },-                                    "( <= 2.4.3 && > 5.2.5 && == 1.4.6 && > 1.1.4 && >= 1.2.2 )": {-                                        "dlCSize": -5,-                                        "dlHash": "txr",-                                        "dlOutput": "$-F쟵_\u001b",-                                        "dlSubdir": {-                                            "RegexDir": "|r0튆"-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:"-                                    },-                                    "( > 3.3.5 && == 6.2.4 && == 5.2.3 && >= 1.4.3 && == 2.1.4 && <= 1.4.2 ) || ( < 2.3.1 && == 2.1.2 && > 1.2.1 && == 1.4.3 && == 2.2.1 ) || ( > 3.3.3 && >= 1.3.2 && >= 2.2.1 )": {-                                        "dlCSize": 4,-                                        "dlHash": "e",-                                        "dlOutput": "1󸖤n6\u0016r",-                                        "dlSubdir": "𧂭",-                                        "dlTag": null,-                                        "dlUri": "http:er"-                                    },-                                    "( > 4.3.6 && < 2.2.3 ) || ( == 4.2.2 ) || ( > 3.3.2 && < 1.2.2 && <= 1.2.2 && >= 3.2.3 )": {-                                        "dlCSize": 6,-                                        "dlHash": "p",-                                        "dlOutput": "",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "old",-                                            "Prerelease",-                                            "base-4.1.4",-                                            "Latest"-                                        ],-                                        "dlUri": "http:oprlws"-                                    }-                                }-                            }-                        },-                        "viChangeLog": "http:ooo",-                        "viPostInstall": null,-                        "viPostRemove": "ecszq",-                        "viPreCompile": "ws",-                        "viPreInstall": "lsa",-                        "viReleaseDay": "12787782918143810-09-08",-                        "viSourceDL": {-                            "dlCSize": null,-                            "dlHash": "xpefg",-                            "dlOutput": null,-                            "dlSubdir": null,-                            "dlTag": [-                                "old",-                                "Latest",-                                "base-3.5.6"-                            ],-                            "dlUri": "https:wtycq"-                        },-                        "viTags": [-                            "Prerelease",-                            "Recommended"-                        ],-                        "viTestDL": {-                            "dlCSize": 5,-                            "dlHash": "zaeaus",-                            "dlOutput": "􉲟㭬+$",-                            "dlSubdir": {-                                "RegexDir": ""-                            },-                            "dlTag": [-                                "Prerelease",-                                "LatestNightly",-                                "old"-                            ],-                            "dlUri": "https:s"-                        }-                    },-                    "7.3.8": {-                        "viArch": {-                            "A_32": {-                                "Darwin": {},-                                "FreeBSD": {-                                    "( < 2.5.6 && >= 4.5.3 && <= 6.1.1 && <= 2.1.2 && < 4.3.3 && == 4.5.1 )": {-                                        "dlCSize": 5,-                                        "dlHash": "yeh",-                                        "dlOutput": "\u0011\u000b䫯PaL􀟏",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Experimental",-                                            "Latest",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:yhqucay"-                                    },-                                    "( < 4.3.5 && > 1.3.2 && <= 5.1.1 && <= 3.3.5 && <= 3.1.1 && == 6.3.2 && >= 4.5.1 )": {-                                        "dlCSize": 7,-                                        "dlHash": "wgvkqrs",-                                        "dlOutput": "$",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Latest",-                                            "Experimental",-                                            "old",-                                            "base-3.4.1",-                                            "M",-                                            "old"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "( <= 3.2.5 && < 4.1.1 && == 4.4.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "mdmvr",-                                        "dlOutput": "9",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestNightly",-                                            "Latest",-                                            "Recommended",-                                            "base-5.5.3",-                                            "Recommended",-                                            "Latest"-                                        ],-                                        "dlUri": "http:ctj"-                                    },-                                    "( <= 3.4.3 && >= 4.5.5 && > 3.4.4 ) || ( == 1.3.2 && <= 1.1.1 )": {-                                        "dlCSize": -6,-                                        "dlHash": "gbgmx",-                                        "dlOutput": "-0",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Experimental",-                                            "LatestNightly",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:del"-                                    },-                                    "( == 2.2.5 && >= 3.1.2 && == 5.2.4 && > 5.4.5 )": {-                                        "dlCSize": 6,-                                        "dlHash": "np",-                                        "dlOutput": "'",-                                        "dlSubdir": "ro",-                                        "dlTag": [],-                                        "dlUri": "http:vfsphgh"-                                    },-                                    "( > 4.4.4 && <= 4.2.2 && >= 4.3.1 && >= 3.3.4 && <= 4.2.5 && <= 5.2.4 && > 2.4.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "zneuvo",-                                        "dlOutput": "",-                                        "dlSubdir": "u♅, i",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "old"-                                        ],-                                        "dlUri": "http:vz"-                                    }-                                },-                                "Linux_Exherbo": {-                                    "( < 3.3.4 )": {-                                        "dlCSize": -3,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": "\u001e",-                                        "dlTag": null,-                                        "dlUri": "https:dtkmdi"-                                    },-                                    "( == 2.2.4 && > 2.5.5 && < 2.3.3 && < 4.4.2 && > 3.2.5 && < 3.1.1 && >= 4.5.4 )": {-                                        "dlCSize": -4,-                                        "dlHash": "xzb",-                                        "dlOutput": "kw\u00160",-                                        "dlSubdir": "\u000e\u001f\u0007󷍈He",-                                        "dlTag": [-                                            "Prerelease",-                                            "old"-                                        ],-                                        "dlUri": "https:sjdi"-                                    },-                                    "( > 3.3.6 && <= 1.2.5 )": {-                                        "dlCSize": -4,-                                        "dlHash": "lqm",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "RBU􆐞"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:qjmdw"-                                    },-                                    "( > 5.3.1 ) || ( > 4.1.3 && == 4.3.4 ) || ( <= 2.1.3 && > 2.2.1 && < 2.2.4 && > 1.1.3 )": {-                                        "dlCSize": -5,-                                        "dlHash": "gr",-                                        "dlOutput": null,-                                        "dlSubdir": "\u0015",-                                        "dlTag": [-                                            "Latest",-                                            "old",-                                            ":k􄃪E󻄫y",-                                            "Nightly",-                                            "Nightly",-                                            "LatestNightly",-                                            "base-2.6.5"-                                        ],-                                        "dlUri": "http:pk"-                                    },-                                    "( >= 3.5.5 && == 3.6.5 )": {-                                        "dlCSize": 5,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": "󺤵6\u0015\u001a,",-                                        "dlTag": null,-                                        "dlUri": "https:od"-                                    },-                                    "( >= 4.2.3 && == 5.4.2 && == 1.4.4 && == 5.5.5 && >= 2.2.1 && == 4.2.5 && < 4.1.1 ) || ( <= 1.1.1 && < 3.1.2 && > 4.2.3 && < 4.1.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "nse",-                                        "dlOutput": "K\u0000K𨗑や1\u001f",-                                        "dlSubdir": {-                                            "RegexDir": "I%𡏞v"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:i"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -5,-                                        "dlHash": "onferhn",-                                        "dlOutput": "$t𪒼3OQp",-                                        "dlSubdir": "􃩓N.",-                                        "dlTag": [],-                                        "dlUri": "https:d"-                                    }-                                },-                                "Linux_UnknownLinux": {-                                    "( == 1.4.2 && < 3.2.2 && < 3.1.2 )": {-                                        "dlCSize": 3,-                                        "dlHash": "l",-                                        "dlOutput": "􏛯𭨕v5m$",-                                        "dlSubdir": "dC/b",-                                        "dlTag": [-                                            "Experimental",-                                            "LatestPrerelease",-                                            "Y[",-                                            "F\u0001\u0016U󹔚𣁥",-                                            "old",-                                            "𐅾9\u000f",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:a"-                                    },-                                    "( == 3.5.2 && > 1.2.4 && >= 3.3.5 && < 1.3.1 && < 3.3.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "ii",-                                        "dlOutput": "5,𡞉",-                                        "dlSubdir": "\u001c👧c\r𠹰*",-                                        "dlTag": [-                                            "&u\r0𩮣􉳒",-                                            "base-6.5.1"-                                        ],-                                        "dlUri": "http:ebv"-                                    },-                                    "( > 2.2.5 && < 3.5.2 && == 6.1.4 && > 4.1.5 && > 2.5.4 && < 4.1.3 )": {-                                        "dlCSize": 6,-                                        "dlHash": "gvdp",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": ",]gb"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:z"-                                    },-                                    "( > 6.2.3 && > 3.1.3 )": {-                                        "dlCSize": -6,-                                        "dlHash": "amt",-                                        "dlOutput": "2󿣶",-                                        "dlSubdir": {-                                            "RegexDir": "􈋢􂯠8􌙕yd"-                                        },-                                        "dlTag": [-                                            "Recommended"-                                        ],-                                        "dlUri": "https:ccnav"-                                    },-                                    "( >= 5.2.1 && >= 5.4.6 && >= 5.3.4 )": {-                                        "dlCSize": -2,-                                        "dlHash": "ravod",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "𝛜\t󲟞"-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:zsrii"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -6,-                                        "dlHash": "yyotl",-                                        "dlOutput": "?",-                                        "dlSubdir": "󹜒G\u0008\u001c",-                                        "dlTag": [-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:u"-                                    }-                                },-                                "Windows": {-                                    "( <= 2.6.2 && <= 3.2.4 && <= 1.5.3 && == 5.3.1 && == 1.3.2 && > 2.5.1 && > 1.4.3 ) || ( > 2.4.3 && < 3.4.2 && >= 4.2.4 && > 2.1.2 )": {-                                        "dlCSize": 6,-                                        "dlHash": "khoycsv",-                                        "dlOutput": "G.d\u0002􉫝",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Recommended",-                                            "base-5.6.1",-                                            "base-6.2.1",-                                            "Nightly",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:zc"-                                    },-                                    "( <= 3.1.1 && < 3.2.5 && < 2.4.1 && < 2.6.5 && == 1.1.1 && == 4.4.2 ) || ( > 4.4.1 )": {-                                        "dlCSize": -5,-                                        "dlHash": "t",-                                        "dlOutput": "3`>)",-                                        "dlSubdir": {-                                            "RegexDir": "\u000cq\u0012"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "Prerelease",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:dmcejqc"-                                    },-                                    "( <= 4.1.2 && > 1.5.2 && < 4.2.1 && > 5.4.3 )": {-                                        "dlCSize": 6,-                                        "dlHash": "n",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "old",-                                            "Latest",-                                            "Prerelease",-                                            "Nightly",-                                            "old",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:yon"-                                    },-                                    "( >= 2.3.2 && == 1.2.4 && >= 2.5.5 && == 1.5.3 && < 3.1.4 ) || ( == 3.2.1 && <= 3.1.2 && >= 4.3.3 && < 1.4.4 && <= 2.1.4 )": {-                                        "dlCSize": -6,-                                        "dlHash": "udb",-                                        "dlOutput": "􌔥\u001df𩛡,sb",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Recommended",-                                            "Nightly",-                                            "𨿦"-                                        ],-                                        "dlUri": "http:mcg"-                                    },-                                    "( >= 3.2.5 ) || ( == 1.4.2 && < 3.1.3 && >= 3.2.1 && < 2.1.3 && <= 3.2.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "btydrgm",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "w .qNo"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:naalwx"-                                    },-                                    "( >= 4.5.2 && >= 1.3.5 && < 2.2.4 && < 4.1.5 ) || ( < 1.3.3 && == 2.2.4 && == 1.1.1 )": {-                                        "dlCSize": -3,-                                        "dlHash": "k",-                                        "dlOutput": "X􁮏!῏",-                                        "dlSubdir": {-                                            "RegexDir": "M"-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:lmbymb"-                                    }-                                }-                            },-                            "A_PowerPC64": {-                                "Linux_Debian": {-                                    "( < 3.5.3 && <= 5.4.4 && <= 5.1.3 && >= 4.1.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": "\t\u000e􍵺+T𢥅\\",-                                        "dlSubdir": {-                                            "RegexDir": "l\u001bb󵒹"-                                        },-                                        "dlTag": [-                                            "base-4.3.3",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:hqgfrm"-                                    },-                                    "( < 5.3.1 && <= 3.5.1 && <= 1.4.4 && >= 5.1.5 && <= 2.3.1 && > 5.5.4 ) || ( > 2.1.3 && >= 1.3.2 && <= 2.1.3 )": {-                                        "dlCSize": 6,-                                        "dlHash": "xl",-                                        "dlOutput": "",-                                        "dlSubdir": "wn𤄥M",-                                        "dlTag": [-                                            "Latest",-                                            "old",-                                            "LatestPrerelease",-                                            "Latest",-                                            "LatestNightly",-                                            "old",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:rfeatin"-                                    },-                                    "( == 1.1.5 )": {-                                        "dlCSize": -1,-                                        "dlHash": "sl",-                                        "dlOutput": "𬨓8",-                                        "dlSubdir": {-                                            "RegexDir": "냌]SC𬜛󱱖"-                                        },-                                        "dlTag": [-                                            "Recommended",-                                            "base-1.1.5",-                                            "Prerelease",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( == 3.1.4 ) || ( >= 1.1.3 && <= 2.2.1 && >= 2.2.2 ) || ( == 2.2.2 && > 3.2.2 ) || ( > 1.2.2 && <= 1.3.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "y",-                                        "dlOutput": "(\u0008",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:zsmw"-                                    },-                                    "( == 4.5.5 && <= 1.2.3 && > 3.5.3 && == 2.5.5 && <= 1.3.5 ) || ( < 3.4.4 && >= 2.2.4 && == 1.4.1 && == 4.3.3 && == 3.1.3 ) || ( == 3.3.3 && < 3.3.1 && >= 2.1.1 && == 3.3.3 ) || ( >= 1.3.2 && < 2.1.1 && > 2.3.3 ) || ( >= 1.1.2 && == 2.2.1 ) || ( > 1.1.1 && >= 1.1.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "hpz",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Latest"-                                        ],-                                        "dlUri": "http:fsvpjnh"-                                    },-                                    "( == 6.3.5 && == 1.5.1 && < 4.3.1 && <= 1.4.2 && > 5.3.2 && <= 5.1.5 ) || ( >= 4.3.3 && > 3.1.3 ) || ( > 1.1.3 && >= 1.1.2 && >= 2.4.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "hs",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "𖠝p\u0017"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "LatestNightly",-                                            "Prerelease",-                                            "Prerelease",-                                            "old",-                                            ">"-                                        ],-                                        "dlUri": "http:aw"-                                    },-                                    "( >= 5.2.1 && >= 3.6.2 )": {-                                        "dlCSize": 2,-                                        "dlHash": "tq",-                                        "dlOutput": "\u0007]",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Experimental",-                                            "LatestNightly",-                                            "old",-                                            "base-3.2.1",-                                            "LatestNightly",-                                            "\u0002󼁽S?b",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -2,-                                        "dlHash": "",-                                        "dlOutput": " l󳨦\u000f\u0017",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:urjz"-                                    }-                                }-                            },-                            "A_Sparc": {-                                "Darwin": {-                                    "( < 1.2.3 && >= 3.1.2 )": {-                                        "dlCSize": 0,-                                        "dlHash": "zijlfow",-                                        "dlOutput": "Ra",-                                        "dlSubdir": "y𒌔􆤹[",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Nightly",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:qg"-                                    }-                                },-                                "FreeBSD": {-                                    "( > 2.1.4 && >= 2.3.1 )": {-                                        "dlCSize": 7,-                                        "dlHash": "jabzipn",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:k"-                                    },-                                    "( >= 3.2.2 && < 2.5.2 && >= 4.5.4 && >= 1.4.2 ) || ( == 2.3.4 && < 3.1.3 && >= 4.1.1 && > 3.4.1 && == 4.2.3 && == 4.4.4 ) || ( == 1.5.4 && < 3.2.2 && < 3.2.3 && == 3.3.2 )": {-                                        "dlCSize": 4,-                                        "dlHash": "tou",-                                        "dlOutput": null,-                                        "dlSubdir": "",-                                        "dlTag": [],-                                        "dlUri": "https:txx"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 0,-                                        "dlHash": "lub",-                                        "dlOutput": "J𥬚5h",-                                        "dlSubdir": {-                                            "RegexDir": "+|o"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:g"-                                    }-                                },-                                "Windows": {}-                            },-                            "A_Sparc64": {-                                "Darwin": {-                                    "( <= 3.2.2 ) || ( <= 5.3.3 && <= 1.4.4 && < 4.2.3 && < 1.3.4 && >= 3.4.2 && == 4.2.4 ) || ( <= 2.2.2 && >= 3.3.2 && < 3.3.2 && == 2.1.1 && > 1.1.3 )": {-                                        "dlCSize": 3,-                                        "dlHash": "ip",-                                        "dlOutput": "\u001a*􍗟A󴚾𱜘",-                                        "dlSubdir": {-                                            "RegexDir": "aa\u0018D"-                                        },-                                        "dlTag": [-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:ho"-                                    },-                                    "( == 4.5.3 && < 4.4.5 && >= 5.3.1 && >= 4.2.1 && > 3.3.2 )": {-                                        "dlCSize": 2,-                                        "dlHash": "twyuus",-                                        "dlOutput": "2GD",-                                        "dlSubdir": {-                                            "RegexDir": "\u0006\u001b_"-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "old",-                                            "old",-                                            "Experimental",-                                            "base-4.3.4"-                                        ],-                                        "dlUri": "http:pinxdt"-                                    },-                                    "( >= 3.1.5 ) || ( > 5.4.3 && >= 2.1.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "lyvuydo",-                                        "dlOutput": null,-                                        "dlSubdir": "}",-                                        "dlTag": [-                                            "Latest",-                                            "old",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:x"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 1,-                                        "dlHash": "rcfm",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "old"-                                        ],-                                        "dlUri": "https:fivv"-                                    }-                                }-                            }-                        },-                        "viChangeLog": "https:rl",-                        "viPostInstall": "ztlnqav",-                        "viPostRemove": "odhugyq",-                        "viPreCompile": "xpdodj",-                        "viPreInstall": "",-                        "viReleaseDay": null,-                        "viSourceDL": null,-                        "viTags": [],-                        "viTestDL": {-                            "dlCSize": -2,-                            "dlHash": "",-                            "dlOutput": "J􃚽\u001d+\u0012\u0008",-                            "dlSubdir": {-                                "RegexDir": ""-                            },-                            "dlTag": [],-                            "dlUri": "http:tzhapz"-                        }-                    },-                    "7.7.2": {-                        "viArch": {-                            "A_32": {-                                "Darwin": {},-                                "FreeBSD": {-                                    "( < 3.1.4 ) || ( < 2.1.3 && >= 1.3.2 )": {-                                        "dlCSize": -2,-                                        "dlHash": "dbvnduo",-                                        "dlOutput": "􇏦r",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease",-                                            "Experimental",-                                            "base-3.5.2",-                                            "J\u000b",-                                            "Latest"-                                        ],-                                        "dlUri": "http:osiho"-                                    },-                                    "( == 2.1.3 && < 2.2.5 && >= 1.3.3 ) || ( < 3.5.2 && <= 1.1.4 && <= 1.2.4 && > 2.2.3 && < 4.2.2 ) || ( >= 2.1.3 ) || ( < 1.2.2 && >= 1.1.2 && == 1.1.2 ) || ( == 1.1.1 && >= 1.1.1 && <= 1.1.1 )": {-                                        "dlCSize": -2,-                                        "dlHash": "qf",-                                        "dlOutput": ">",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "https:prcjfea"-                                    },-                                    "( == 3.4.2 && > 5.5.2 ) || ( <= 4.1.2 && <= 4.4.3 && >= 2.4.4 && >= 4.3.3 && < 1.2.3 && == 3.3.1 )": {-                                        "dlCSize": 7,-                                        "dlHash": "eaypp",-                                        "dlOutput": "\u001a",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Experimental",-                                            "Latest",-                                            "Nightly",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:iytcu"-                                    },-                                    "( == 3.4.4 && < 3.1.3 && >= 4.1.2 && < 2.4.3 && == 1.3.2 && == 3.5.1 ) || ( >= 3.4.2 && < 2.4.1 && > 4.1.3 && <= 1.1.2 ) || ( > 1.1.3 && == 3.2.3 && <= 2.4.2 && < 3.1.3 && == 2.3.2 ) || ( >= 1.2.2 && == 1.1.1 ) || ( >= 1.1.1 && >= 2.2.1 && < 1.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "ffqdvs",-                                        "dlOutput": null,-                                        "dlSubdir": ".󷸽",-                                        "dlTag": null,-                                        "dlUri": "http:smutz"-                                    },-                                    "( == 5.3.4 && >= 3.1.2 && <= 4.5.2 && > 4.5.2 && < 1.1.1 && >= 5.3.4 && >= 3.3.4 )": {-                                        "dlCSize": -4,-                                        "dlHash": "gzhqpr",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "https:faai"-                                    },-                                    "( >= 2.4.1 ) || ( > 2.3.1 && < 4.2.2 && > 1.1.2 && > 4.4.1 ) || ( <= 1.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": "&",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestNightly",-                                            "Experimental",-                                            "LatestNightly",-                                            "x􂀟"-                                        ],-                                        "dlUri": "http:p"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "o",-                                        "dlOutput": "\u0011K",-                                        "dlSubdir": {-                                            "RegexDir": "􊵤􈿅]#"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:go"-                                    }-                                },-                                "Linux_Debian": {-                                    "( < 1.5.2 && >= 4.5.1 && > 5.1.3 && > 2.1.3 && >= 3.4.1 ) || ( == 1.4.3 && <= 1.2.2 && > 3.2.1 ) || ( > 1.3.2 ) || ( > 1.2.1 && <= 1.1.2 && <= 1.1.3 )": {-                                        "dlCSize": -4,-                                        "dlHash": "x",-                                        "dlOutput": "QG",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Recommended"-                                        ],-                                        "dlUri": "http:qewuvum"-                                    },-                                    "( == 3.2.6 && > 1.1.3 && > 3.5.3 && <= 2.2.3 && >= 3.6.5 && > 2.4.3 && <= 2.1.5 )": {-                                        "dlCSize": -4,-                                        "dlHash": "o",-                                        "dlOutput": "􃖍*\u0015G",-                                        "dlSubdir": "<2􉘘𠥮>p",-                                        "dlTag": [-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:chg"-                                    }-                                },-                                "Linux_RedHat": {-                                    "( <= 5.2.1 && == 5.5.3 && == 4.2.1 && > 5.2.1 && > 3.5.3 && <= 5.2.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "y",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-4.1.7"-                                        ],-                                        "dlUri": "http:rordqv"-                                    },-                                    "( > 1.2.2 ) || ( < 1.3.4 && >= 2.3.2 && < 2.1.3 ) || ( <= 1.1.3 ) || ( == 4.1.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": "&Q\r=",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-5.3.3",-                                            "",-                                            "LatestNightly",-                                            "Latest",-                                            "Prerelease",-                                            "Latest"-                                        ],-                                        "dlUri": "https:mo"-                                    },-                                    "( > 5.3.1 && >= 5.1.4 && < 3.4.5 )": {-                                        "dlCSize": 6,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "]~"-                                        },-                                        "dlTag": [],-                                        "dlUri": "http:dmfetf"-                                    },-                                    "( >= 2.3.5 && == 4.2.3 ) || ( > 4.1.4 && == 3.4.2 )": {-                                        "dlCSize": 5,-                                        "dlHash": "nsqmqgm",-                                        "dlOutput": "\n􊠷󳖸𒄥)I",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "https:eljuqxa"-                                    }-                                },-                                "Windows": {-                                    "( == 5.2.2 && == 6.2.1 ) || ( == 4.3.2 && < 4.1.4 && > 3.1.1 && <= 3.4.3 ) || ( > 3.1.1 && >= 3.3.3 && >= 1.1.2 )": {-                                        "dlCSize": -4,-                                        "dlHash": "tdojrll",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "https:nsnhjmj"-                                    },-                                    "( > 1.1.1 && < 1.3.5 && <= 5.1.1 && >= 3.2.1 && <= 2.3.5 ) || ( == 4.2.4 )": {-                                        "dlCSize": -1,-                                        "dlHash": "",-                                        "dlOutput": "\u000ct􎖨",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Prerelease",-                                            "Recommended",-                                            "base-5.2.2",-                                            "LatestPrerelease",-                                            "Recommended",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:bi"-                                    },-                                    "( > 3.1.1 )": {-                                        "dlCSize": 3,-                                        "dlHash": "apr",-                                        "dlOutput": "",-                                        "dlSubdir": "'fl4",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "\u000ec󵺤",-                                            "old",-                                            "old",-                                            "P󾡏`",-                                            "Latest"-                                        ],-                                        "dlUri": "http:mdpe"-                                    }-                                }-                            },-                            "A_64": {-                                "Darwin": {-                                    "( <= 4.3.2 && >= 4.3.2 ) || ( >= 4.3.1 && <= 1.2.5 && < 1.1.3 )": {-                                        "dlCSize": -3,-                                        "dlHash": "qy",-                                        "dlOutput": "󰥝",-                                        "dlSubdir": "PP󲭛",-                                        "dlTag": [-                                            "Recommended",-                                            "LatestNightly",-                                            "base-1.3.2",-                                            "xp",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:mdula"-                                    }-                                },-                                "FreeBSD": {-                                    "( < 4.2.1 && < 5.1.2 && >= 1.4.1 && < 4.3.2 && == 3.3.6 && == 4.1.5 )": {-                                        "dlCSize": 5,-                                        "dlHash": "crt",-                                        "dlOutput": null,-                                        "dlSubdir": "\u0014",-                                        "dlTag": [-                                            "base-6.1.4",-                                            "old"-                                        ],-                                        "dlUri": "https:zt"-                                    },-                                    "( < 5.4.3 && > 1.2.1 && > 3.3.4 && <= 1.1.1 )": {-                                        "dlCSize": -7,-                                        "dlHash": "udl",-                                        "dlOutput": "j",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-6.6.5"-                                        ],-                                        "dlUri": "https:ap"-                                    },-                                    "( > 1.1.4 && >= 4.4.1 && < 5.3.4 && == 1.5.3 && > 5.3.5 && == 1.2.4 && <= 2.3.4 ) || ( > 1.5.3 ) || ( > 3.3.1 && <= 3.2.3 && < 3.3.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "qxc",-                                        "dlOutput": "\u000c\u0014",-                                        "dlSubdir": {-                                            "RegexDir": "8\u001f\u0003\u0011 E"-                                        },-                                        "dlTag": [-                                            "o\u0017S",-                                            "Recommended",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:oykvswd"-                                    },-                                    "( >= 3.4.3 ) || ( <= 3.2.4 ) || ( >= 3.1.3 && <= 1.1.3 && == 2.3.2 && < 2.2.3 )": {-                                        "dlCSize": 6,-                                        "dlHash": "lg",-                                        "dlOutput": "\u0015M'K𩆛",-                                        "dlSubdir": "󷮭󷎗ly",-                                        "dlTag": [-                                            "Prerelease",-                                            "Experimental",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:s"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -4,-                                        "dlHash": "qg",-                                        "dlOutput": "􌞆L",-                                        "dlSubdir": "=+G\u0002Q",-                                        "dlTag": [-                                            "Latest"-                                        ],-                                        "dlUri": "https:cmfk"-                                    }-                                },-                                "Linux_AmazonLinux": {-                                    "( < 1.4.2 && < 3.1.4 && > 1.4.5 )": {-                                        "dlCSize": -5,-                                        "dlHash": "piynn",-                                        "dlOutput": "৴4\u000b&\u001c𐎳",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "L𮅥"-                                        ],-                                        "dlUri": "http:sg"-                                    },-                                    "( < 5.2.4 && > 3.3.1 && < 2.1.1 && <= 1.4.4 && > 4.1.2 && <= 3.4.2 && >= 5.4.2 ) || ( >= 2.4.3 && <= 2.3.3 && < 1.1.4 && >= 1.3.1 )": {-                                        "dlCSize": 5,-                                        "dlHash": "vvwg",-                                        "dlOutput": "𰱪7>445",-                                        "dlSubdir": "𢬈l",-                                        "dlTag": [-                                            "Recommended"-                                        ],-                                        "dlUri": "https:hycodxn"-                                    },-                                    "( == 1.2.5 && <= 5.3.1 && <= 3.3.4 && < 4.5.1 && >= 3.3.2 ) || ( == 3.3.4 && > 3.1.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": "B=𞁄~G󿺘p",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:pfx"-                                    },-                                    "( > 5.2.5 ) || ( < 3.1.1 && <= 2.3.2 ) || ( < 3.1.3 && <= 1.1.2 && == 2.1.3 )": {-                                        "dlCSize": -6,-                                        "dlHash": "ulz",-                                        "dlOutput": "?2\u0014!\u0002",-                                        "dlSubdir": {-                                            "RegexDir": "会5}"-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:wa"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "n",-                                        "dlOutput": "+m",-                                        "dlSubdir": "",-                                        "dlTag": null,-                                        "dlUri": "https:wcz"-                                    }-                                },-                                "Linux_Debian": {-                                    "( >= 1.2.1 && < 4.4.2 && <= 3.3.5 && >= 1.4.1 && > 5.2.3 && >= 5.6.5 ) || ( <= 3.1.3 && >= 4.4.2 && <= 1.3.2 && == 4.3.4 && < 2.4.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "apha",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-6.6.6",-                                            "Latest",-                                            "𠁸穑A",-                                            "base-5.6.3",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:htp"-                                    }-                                },-                                "Windows": {-                                    "( <= 1.1.4 && < 3.5.2 )": {-                                        "dlCSize": 5,-                                        "dlHash": "vlpqfu",-                                        "dlOutput": "P󸨳TZ𬝦6𱟋",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "Latest",-                                            "LatestNightly",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:ylnxlr"-                                    },-                                    "( <= 1.3.1 && < 1.3.3 )": {-                                        "dlCSize": 4,-                                        "dlHash": "u",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Recommended",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:rqj"-                                    },-                                    "( <= 2.4.1 && > 3.3.2 && == 4.3.5 )": {-                                        "dlCSize": 1,-                                        "dlHash": "jvmht",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    },-                                    "( == 2.3.2 && <= 1.2.2 && < 5.1.2 && > 2.3.2 && > 5.2.1 && >= 4.1.4 && < 4.1.5 ) || ( == 1.4.2 && < 4.3.3 && >= 2.1.1 && < 4.1.3 && < 4.3.1 ) || ( == 3.2.2 && == 1.2.2 && >= 2.1.1 )": {-                                        "dlCSize": 4,-                                        "dlHash": "heqe",-                                        "dlOutput": null,-                                        "dlSubdir": "𗄗/prj",-                                        "dlTag": null,-                                        "dlUri": "http:qk"-                                    },-                                    "( > 4.5.1 && >= 3.4.1 && >= 4.1.2 && >= 3.3.5 && > 1.1.5 ) || ( <= 4.3.4 && >= 3.1.4 && < 1.3.2 && <= 2.4.3 && <= 4.2.3 && < 1.4.2 ) || ( > 1.3.2 ) || ( == 3.2.1 && == 1.2.3 && <= 1.1.1 ) || ( < 1.1.2 && < 1.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "ewbjr",-                                        "dlOutput": "OZ",-                                        "dlSubdir": "8𨜝Ng󷐟_",-                                        "dlTag": null,-                                        "dlUri": "http:puqsp"-                                    },-                                    "( > 5.2.5 && < 1.4.5 && < 4.1.5 && <= 1.4.1 && >= 3.4.3 && <= 5.5.5 && < 2.2.5 ) || ( <= 1.2.2 && < 4.1.4 && > 2.3.2 && == 6.3.2 && <= 4.2.2 && == 1.4.4 ) || ( == 2.2.2 && <= 1.2.1 && > 1.1.3 && <= 3.1.1 && == 2.2.2 ) || ( <= 2.3.2 && > 2.1.1 )": {-                                        "dlCSize": -4,-                                        "dlHash": "b",-                                        "dlOutput": "\u0008",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -7,-                                        "dlHash": "mjg",-                                        "dlOutput": "\\\u001c𥖫\u0016'\u0016q",-                                        "dlSubdir": "5",-                                        "dlTag": [-                                            "LatestNightly",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:plmnf"-                                    }-                                }-                            },-                            "A_ARM64": {-                                "Darwin": {-                                    "( < 2.1.3 && == 2.1.2 && <= 3.5.1 && < 5.6.5 && <= 3.2.4 && >= 5.6.1 )": {-                                        "dlCSize": 1,-                                        "dlHash": "qimcc",-                                        "dlOutput": "㠥\u0012_𖣊?.",-                                        "dlSubdir": "􅯆㪟&󱠷􊆱𭙑",-                                        "dlTag": [-                                            "old"-                                        ],-                                        "dlUri": "https:ye"-                                    },-                                    "( <= 2.4.3 ) || ( <= 3.4.3 )": {-                                        "dlCSize": 6,-                                        "dlHash": "nnrtyvt",-                                        "dlOutput": "<\u0006𰉴",-                                        "dlSubdir": {-                                            "RegexDir": "\u0010D:^k\n"-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "Experimental",-                                            "LatestPrerelease",-                                            "base-6.5.5",-                                            "LatestPrerelease",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:biwkp"-                                    },-                                    "( <= 3.1.3 && == 3.2.4 ) || ( < 3.3.1 && < 1.2.4 )": {-                                        "dlCSize": 7,-                                        "dlHash": "tiuw",-                                        "dlOutput": "𘩻_LE ",-                                        "dlSubdir": {-                                            "RegexDir": ">x"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:r"-                                    },-                                    "( <= 3.2.2 && <= 5.1.3 && >= 2.6.3 && >= 5.4.2 && > 1.5.4 && > 4.4.3 ) || ( >= 2.4.2 && >= 4.1.4 && <= 4.4.5 )": {-                                        "dlCSize": 1,-                                        "dlHash": "cwzo",-                                        "dlOutput": "Y\u000b,%󾑴",-                                        "dlSubdir": "􋢝)",-                                        "dlTag": null,-                                        "dlUri": "https:hk"-                                    },-                                    "( == 3.2.5 && <= 3.3.3 && == 2.1.5 && >= 4.4.2 && > 5.5.5 && <= 4.1.3 && < 2.2.4 ) || ( < 3.4.2 && > 4.3.3 && > 4.4.4 && == 2.3.3 && <= 2.3.4 && >= 2.2.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "yzj",-                                        "dlOutput": "+󴅜J",-                                        "dlSubdir": ",u\n9|𤣾",-                                        "dlTag": [-                                            "LatestNightly",-                                            "𤀐\t𣕶n",-                                            "base-1.3.3",-                                            "old"-                                        ],-                                        "dlUri": "https:kiqtic"-                                    },-                                    "( > 2.1.4 )": {-                                        "dlCSize": 4,-                                        "dlHash": "nxvecil",-                                        "dlOutput": ".4n(\r\u0011",-                                        "dlSubdir": "8\"}",-                                        "dlTag": [-                                            "LatestNightly",-                                            "base-3.5.2",-                                            "LatestNightly",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:hpvk"-                                    },-                                    "( >= 3.4.1 && > 4.5.3 && == 1.1.2 && > 3.1.2 && > 4.5.4 && >= 5.3.1 && == 5.3.1 )": {-                                        "dlCSize": -1,-                                        "dlHash": "kfydgw",-                                        "dlOutput": "dei󻂼V",-                                        "dlSubdir": {-                                            "RegexDir": "ZO7􀧫􈼄W"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:mgnecl"-                                    }-                                },-                                "FreeBSD": {-                                    "( == 3.1.4 && < 3.5.5 && == 2.3.2 && < 1.5.3 && >= 3.5.4 ) || ( <= 4.4.4 && == 3.4.2 && < 3.3.4 ) || ( >= 3.1.1 && <= 3.2.2 && < 2.1.2 && <= 1.3.1 )": {-                                        "dlCSize": 3,-                                        "dlHash": "kr",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "z"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "LatestNightly",-                                            "Latest",-                                            "Prerelease",-                                            "LatestNightly",-                                            "Recommended",-                                            "base-4.6.3"-                                        ],-                                        "dlUri": "https:zcf"-                                    },-                                    "( == 4.3.4 && <= 1.1.1 && < 1.3.3 && > 2.2.1 && > 5.1.2 )": {-                                        "dlCSize": -5,-                                        "dlHash": "gj",-                                        "dlOutput": "U)TD",-                                        "dlSubdir": {-                                            "RegexDir": "rh\u000e"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:nsvwhth"-                                    },-                                    "( > 4.2.5 && < 3.4.4 && <= 1.1.2 && >= 4.4.1 && >= 2.4.2 )": {-                                        "dlCSize": -6,-                                        "dlHash": "q",-                                        "dlOutput": ")",-                                        "dlSubdir": "J䆵\u0015<",-                                        "dlTag": [-                                            "old",-                                            "LatestNightly",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:vega"-                                    },-                                    "( >= 3.4.2 && <= 5.5.2 && == 2.5.2 && == 5.2.6 && >= 4.5.4 && == 2.4.3 )": {-                                        "dlCSize": 0,-                                        "dlHash": "fjv",-                                        "dlOutput": null,-                                        "dlSubdir": "!\u0001",-                                        "dlTag": [-                                            "Latest",-                                            "LatestPrerelease",-                                            "B\t",-                                            "old"-                                        ],-                                        "dlUri": "https:eunuxzx"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "lcen",-                                        "dlOutput": "T$\u0006[w",-                                        "dlSubdir": {-                                            "RegexDir": "𘑮3$\u0018"-                                        },-                                        "dlTag": [],-                                        "dlUri": "http:"-                                    }-                                },-                                "Linux_CentOS": {-                                    "( >= 5.2.2 && < 4.1.4 && >= 3.5.4 ) || ( > 4.2.3 && >= 1.4.4 && >= 2.4.1 && >= 4.4.4 ) || ( <= 1.2.3 && <= 1.2.1 )": {-                                        "dlCSize": -1,-                                        "dlHash": "xnvz",-                                        "dlOutput": "\u0017T󻋟dV-",-                                        "dlSubdir": {-                                            "RegexDir": "귎 /𪁨廣"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:wlxa"-                                    }-                                }-                            },-                            "A_PowerPC": {-                                "Darwin": {-                                    "( < 4.1.5 && == 3.4.2 && >= 4.5.3 && > 2.1.4 ) || ( == 2.1.1 && == 1.3.4 && <= 2.4.1 && < 3.1.1 && <= 4.2.4 )": {-                                        "dlCSize": -5,-                                        "dlHash": "hwywc",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-4.2.3",-                                            "Latest",-                                            "old",-                                            "old",-                                            "LatestPrerelease",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:b"-                                    },-                                    "( < 4.4.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "bpee",-                                        "dlOutput": null,-                                        "dlSubdir": "Z\r)",-                                        "dlTag": [-                                            "\u0014\u001f#",-                                            "LatestNightly",-                                            "K󴺁꺤𥊵"-                                        ],-                                        "dlUri": "http:elbz"-                                    },-                                    "( == 5.1.4 && <= 2.4.5 && <= 3.4.5 && == 4.1.3 && == 1.4.2 && > 5.2.5 && > 2.3.3 )": {-                                        "dlCSize": -6,-                                        "dlHash": "mluqghk",-                                        "dlOutput": "oW'\u0017!",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestNightly",-                                            "Nightly",-                                            "𮤵\u0015켿Q",-                                            "base-6.6.1",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:"-                                    }-                                },-                                "FreeBSD": {-                                    "( < 1.5.3 )": {-                                        "dlCSize": 4,-                                        "dlHash": "anvo",-                                        "dlOutput": "𧕈\u000e󾾚𤎄=􂾢",-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:qqx"-                                    },-                                    "( <= 2.2.2 && < 6.1.3 && >= 1.4.4 && < 4.1.3 ) || ( <= 4.4.4 )": {-                                        "dlCSize": 2,-                                        "dlHash": "jeo",-                                        "dlOutput": "%號𨳐1\u0012N",-                                        "dlSubdir": "􃟠[H\u0001\u001a\u001b",-                                        "dlTag": [-                                            "base-2.5.6"-                                        ],-                                        "dlUri": "http:cqngc"-                                    },-                                    "( <= 2.3.5 && < 2.1.3 && <= 3.1.1 && < 3.4.3 && <= 3.1.1 ) || ( == 3.1.4 && >= 4.4.4 && < 3.4.2 && >= 1.4.1 && <= 4.3.3 )": {-                                        "dlCSize": -3,-                                        "dlHash": "",-                                        "dlOutput": "\u0013\u0007𣁤I4",-                                        "dlSubdir": "􅄽󻠡",-                                        "dlTag": [-                                            "old",-                                            "old",-                                            "old",-                                            "Recommended",-                                            "A:%H\u0019",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( >= 5.1.3 && == 5.2.4 && >= 1.3.4 && < 3.1.3 ) || ( <= 4.4.3 && > 1.2.1 && < 3.2.1 ) || ( < 1.2.3 && == 3.2.3 && >= 2.1.4 && == 3.3.1 ) || ( >= 2.2.2 && < 1.1.1 )": {-                                        "dlCSize": 7,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": "𫝎",-                                        "dlTag": [-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:vl"-                                    }-                                }-                            },-                            "A_PowerPC64": {},-                            "A_Sparc64": {-                                "Darwin": {-                                    "( < 1.4.1 && >= 2.5.2 && == 1.1.3 && < 2.3.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "dlfmp",-                                        "dlOutput": "W\u0016䍷",-                                        "dlSubdir": {-                                            "RegexDir": "0:"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "Recommended",-                                            "Experimental",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "http:eymtcb"-                                    },-                                    "( < 5.2.2 && <= 2.5.5 && == 4.3.2 && >= 1.2.3 && < 4.5.1 && < 1.2.1 && < 1.4.2 )": {-                                        "dlCSize": -7,-                                        "dlHash": "qofekmi",-                                        "dlOutput": "\u0000",-                                        "dlSubdir": "|",-                                        "dlTag": null,-                                        "dlUri": "http:piiaa"-                                    },-                                    "( > 1.2.5 && <= 2.5.4 && > 6.5.1 && > 3.3.4 && < 4.2.4 && < 5.2.4 && > 3.3.3 ) || ( == 3.1.2 && < 1.3.2 && == 1.1.2 && >= 2.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "opopu",-                                        "dlOutput": "𩽱",-                                        "dlSubdir": "8􀿍g;~",-                                        "dlTag": [-                                            "old",-                                            "Latest",-                                            "LatestPrerelease",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:wdnkgme"-                                    },-                                    "( >= 2.5.1 && > 6.1.4 && <= 3.4.4 && == 3.4.3 && < 4.3.2 && > 2.4.4 )": {-                                        "dlCSize": -3,-                                        "dlHash": "",-                                        "dlOutput": "itR/􎳩",-                                        "dlSubdir": {-                                            "RegexDir": "2,"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "old"-                                        ],-                                        "dlUri": "http:hqvhw"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 6,-                                        "dlHash": "bwrlwx",-                                        "dlOutput": "𮌕`",-                                        "dlSubdir": {-                                            "RegexDir": "'#C𛊸XM"-                                        },-                                        "dlTag": [-                                            "base-3.6.3",-                                            "Experimental",-                                            "Experimental",-                                            "Nightly",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:ad"-                                    }-                                },-                                "FreeBSD": {-                                    "( > 1.3.1 && == 2.5.1 && > 5.6.4 && == 3.2.1 && == 4.5.3 ) || ( >= 2.5.4 && == 4.2.1 && <= 4.4.4 ) || ( <= 1.1.1 && >= 3.2.3 && > 2.1.2 && > 1.3.1 && == 1.2.2 ) || ( == 1.1.1 )": {-                                        "dlCSize": 6,-                                        "dlHash": "s",-                                        "dlOutput": null,-                                        "dlSubdir": "f>⩽Y/\\",-                                        "dlTag": null,-                                        "dlUri": "http:cmfj"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -3,-                                        "dlHash": "",-                                        "dlOutput": "\u0018际xH:",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-5.6.4",-                                            "Recommended",-                                            "Latest",-                                            "Latest",-                                            "LatestNightly",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:dlutev"-                                    }-                                },-                                "Linux_CentOS": {-                                    "( < 2.3.5 && < 4.3.5 ) || ( >= 3.3.1 && == 4.3.3 && <= 3.4.2 && >= 4.2.4 && <= 1.2.3 && <= 4.3.3 ) || ( == 3.3.2 && <= 3.1.1 ) || ( > 1.2.1 && < 2.1.3 && >= 1.1.2 && > 1.1.2 )": {-                                        "dlCSize": -4,-                                        "dlHash": "ndpgk",-                                        "dlOutput": "n,\u0007\u000c𗮆(",-                                        "dlSubdir": "􁏦𱚞3\u0005}\u0001",-                                        "dlTag": [-                                            "Latest",-                                            "LatestNightly",-                                            "LatestNightly",-                                            "old",-                                            "Recommended",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:inmpi"-                                    },-                                    "( <= 4.3.2 && == 2.5.2 && >= 3.5.1 ) || ( == 1.2.1 && <= 1.2.1 && < 4.3.2 && < 3.1.2 && == 1.4.2 && < 2.3.2 )": {-                                        "dlCSize": 5,-                                        "dlHash": "i",-                                        "dlOutput": "98\u0012",-                                        "dlSubdir": "~2M𘗸L󵡭",-                                        "dlTag": [-                                            "base-6.6.2",-                                            "Recommended",-                                            "Experimental",-                                            "base-1.4.6"-                                        ],-                                        "dlUri": "https:vbydb"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "q",-                                        "dlOutput": "+⣰\u0003\u0010󲈩",-                                        "dlSubdir": "0oik𪸝슝",-                                        "dlTag": null,-                                        "dlUri": "http:bumuzn"-                                    }-                                },-                                "Linux_Rocky": {-                                    "( < 5.4.4 && < 5.3.2 && == 5.3.4 && > 3.3.2 && == 2.4.1 && == 4.3.4 && >= 2.1.3 ) || ( > 2.1.1 )": {-                                        "dlCSize": -6,-                                        "dlHash": "puxdyt",-                                        "dlOutput": null,-                                        "dlSubdir": "]~𧚼𛇌𰽕Y",-                                        "dlTag": [-                                            "LatestNightly",-                                            "Prerelease",-                                            "old",-                                            "Prerelease",-                                            "old"-                                        ],-                                        "dlUri": "https:huxq"-                                    },-                                    "( >= 4.1.2 && >= 5.4.5 && >= 1.2.1 && > 5.4.4 )": {-                                        "dlCSize": 2,-                                        "dlHash": "ezeb",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Latest",-                                            "Latest",-                                            "old",-                                            "Nightly",-                                            "Latest",-                                            "LatestNightly",-                                            "Recommended"-                                        ],-                                        "dlUri": "https:w"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -5,-                                        "dlHash": "d",-                                        "dlOutput": "𨢩\u000c}I\u0003\u0018:",-                                        "dlSubdir": {-                                            "RegexDir": "\u0010歔`t󰴙r"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:twmr"-                                    }-                                },-                                "Linux_Ubuntu": {-                                    "( < 2.4.4 && <= 5.2.2 && < 3.2.3 && >= 5.4.1 && <= 4.5.2 )": {-                                        "dlCSize": 7,-                                        "dlHash": "rfli",-                                        "dlOutput": "7V󹪻TPo",-                                        "dlSubdir": {-                                            "RegexDir": "'􇂨!d"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "",-                                            ")\u0007?",-                                            "Prerelease",-                                            "Experimental",-                                            "Recommended",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:ovsa"-                                    },-                                    "( <= 4.2.2 && > 1.3.3 && == 6.5.5 && < 2.3.4 && == 3.3.4 && > 3.5.1 )": {-                                        "dlCSize": -2,-                                        "dlHash": "qxpptqv",-                                        "dlOutput": "",-                                        "dlSubdir": "\u001f",-                                        "dlTag": [-                                            "Latest",-                                            "Experimental",-                                            "base-5.2.2",-                                            "Latest"-                                        ],-                                        "dlUri": "http:ikqhdfs"-                                    },-                                    "( > 2.4.1 ) || ( >= 4.1.3 )": {-                                        "dlCSize": 3,-                                        "dlHash": "dabzowa",-                                        "dlOutput": "3t",-                                        "dlSubdir": "􈯻A\r\u000b",-                                        "dlTag": null,-                                        "dlUri": "https:uod"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -4,-                                        "dlHash": "r",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "v󾛬nS\u0003"-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:mhj"-                                    }-                                },-                                "Windows": {-                                    "( <= 3.4.1 )": {-                                        "dlCSize": 4,-                                        "dlHash": "qjqupa",-                                        "dlOutput": "x󸒗🮠\u0012",-                                        "dlSubdir": {-                                            "RegexDir": "^w\u001c"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:woywo"-                                    },-                                    "( <= 3.5.2 && <= 1.5.4 && >= 4.4.5 && < 5.1.2 && >= 5.2.1 ) || ( >= 2.2.2 && < 4.3.2 && >= 4.4.3 && == 4.2.3 ) || ( <= 2.2.3 && >= 3.3.2 )": {-                                        "dlCSize": 0,-                                        "dlHash": "shz",-                                        "dlOutput": "裗",-                                        "dlSubdir": "SZ𗕐",-                                        "dlTag": [-                                            "Recommended",-                                            "base-6.4.6"-                                        ],-                                        "dlUri": "https:pkbw"-                                    },-                                    "( == 1.2.3 && == 5.3.5 && < 1.1.1 ) || ( == 1.2.2 )": {-                                        "dlCSize": -7,-                                        "dlHash": "bb",-                                        "dlOutput": null,-                                        "dlSubdir": "\u0018󺆾􄗞\u0019󵈻",-                                        "dlTag": null,-                                        "dlUri": "http:jnsmrl"-                                    },-                                    "( == 2.1.5 && > 4.5.1 && < 1.5.2 && >= 2.4.4 && > 3.1.4 )": {-                                        "dlCSize": -1,-                                        "dlHash": "jnlhedo",-                                        "dlOutput": "\u0005r",-                                        "dlSubdir": "C\u000cD𱒯",-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Nightly",-                                            "LatestPrerelease",-                                            "Prerelease",-                                            "\u0014",-                                            "old",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:huxmfo"-                                    },-                                    "( > 3.6.5 && > 1.3.2 && < 4.1.5 && <= 1.3.5 && >= 4.4.5 ) || ( == 2.1.5 && <= 1.5.1 && <= 3.2.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "utt",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "Q"-                                        },-                                        "dlTag": [-                                            "Recommended"-                                        ],-                                        "dlUri": "http:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 1,-                                        "dlHash": "",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "d\u0005A\u001c"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "Recommended",-                                            "Latest",-                                            "LatestNightly",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:"-                                    }-                                }-                            }-                        },-                        "viChangeLog": null,-                        "viPostInstall": "gce",-                        "viPostRemove": "",-                        "viPreCompile": "fokigel",-                        "viPreInstall": "qda",-                        "viReleaseDay": "1041212727146945-04-15",-                        "viSourceDL": null,-                        "viTags": [-                            "Prerelease",-                            "Latest",-                            "LatestPrerelease",-                            "Prerelease"-                        ],-                        "viTestDL": {-                            "dlCSize": -5,-                            "dlHash": "jm",-                            "dlOutput": null,-                            "dlSubdir": {-                                "RegexDir": "\r\u0005𡈆"-                            },-                            "dlTag": null,-                            "dlUri": "http:keoany"-                        }-                    },-                    "8.5.3": {-                        "viArch": {-                            "A_32": {-                                "Darwin": {-                                    "( <= 5.1.1 && <= 4.3.1 && > 4.3.5 && == 2.5.2 && == 4.5.5 && > 5.2.2 ) || ( <= 2.4.4 )": {-                                        "dlCSize": 1,-                                        "dlHash": "knoi",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Latest",-                                            "LatestPrerelease",-                                            "Prerelease",-                                            "LatestPrerelease",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:gyxbzls"-                                    },-                                    "( == 2.2.5 && >= 4.5.5 && == 2.2.1 && > 5.2.4 && == 4.4.5 && >= 5.2.2 ) || ( < 1.4.4 && == 3.3.4 && >= 3.2.4 && == 4.2.1 && <= 4.3.1 ) || ( == 1.1.1 && <= 2.3.1 && >= 2.2.2 && >= 1.1.1 )": {-                                        "dlCSize": 6,-                                        "dlHash": "pt",-                                        "dlOutput": "𬒨𮷶@v\u0015",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "https:dxxb"-                                    },-                                    "( > 3.1.4 && < 3.1.3 && == 5.2.4 && >= 5.5.5 && >= 1.3.1 && <= 3.3.5 && < 3.5.4 )": {-                                        "dlCSize": -1,-                                        "dlHash": "ycuhy",-                                        "dlOutput": "O\u000f\u0007",-                                        "dlSubdir": {-                                            "RegexDir": ">d"-                                        },-                                        "dlTag": [-                                            "Latest",-                                            "old",-                                            "Nightly",-                                            "Nightly",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:m"-                                    },-                                    "( >= 3.1.1 && < 3.1.1 && <= 5.2.1 )": {-                                        "dlCSize": -7,-                                        "dlHash": "",-                                        "dlOutput": "A𥫌\u000b",-                                        "dlSubdir": {-                                            "RegexDir": "kcy)\u000b󱕑"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "base-1.6.4",-                                            "Nightly",-                                            "Latest"-                                        ],-                                        "dlUri": "https:n"-                                    },-                                    "( >= 3.2.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "zqjcs",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "儉i𘋣9"-                                        },-                                        "dlTag": [-                                            "𭔿𫻦𰫪"-                                        ],-                                        "dlUri": "https:ll"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "vc",-                                        "dlOutput": null,-                                        "dlSubdir": "9[~𭏪5",-                                        "dlTag": [],-                                        "dlUri": "https:mqr"-                                    }-                                },-                                "Linux_AmazonLinux": {-                                    "( == 5.3.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "yy",-                                        "dlOutput": "n#\"G\u0011N󲟪",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    },-                                    "( >= 5.4.2 && == 5.3.6 && == 3.4.3 && == 1.2.2 )": {-                                        "dlCSize": -1,-                                        "dlHash": "cgkyu",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:tbarp"-                                    }-                                },-                                "Linux_Rocky": {-                                    "unknown_versioning": {-                                        "dlCSize": 6,-                                        "dlHash": "gvuhib",-                                        "dlOutput": "r󾺏X",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Experimental",-                                            "Experimental",-                                            "LatestPrerelease",-                                            "LatestNightly",-                                            "Latest",-                                            "old",-                                            "Latest"-                                        ],-                                        "dlUri": "https:clr"-                                    }-                                },-                                "Windows": {-                                    "( <= 4.4.3 && <= 1.4.5 && > 5.3.4 && < 4.4.3 ) || ( > 2.4.2 && <= 2.1.3 ) || ( >= 2.2.4 && >= 3.3.1 && >= 2.2.3 && >= 3.2.2 ) || ( == 1.1.1 && == 1.2.2 && > 3.1.1 && >= 1.1.2 ) || ( <= 1.2.1 && > 1.1.2 && <= 1.1.1 ) || ( <= 1.1.2 && > 1.1.1 ) || ( == 1.1.1 )": {-                                        "dlCSize": 2,-                                        "dlHash": "sfmc",-                                        "dlOutput": null,-                                        "dlSubdir": "%,m",-                                        "dlTag": [-                                            "Recommended",-                                            "LatestNightly",-                                            "Prerelease",-                                            "",-                                            "Latest",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:zulvo"-                                    },-                                    "( == 1.5.6 && > 4.3.2 ) || ( <= 1.1.1 && >= 2.4.3 && >= 1.2.1 && >= 4.4.3 && < 4.3.4 )": {-                                        "dlCSize": -6,-                                        "dlHash": "ysz",-                                        "dlOutput": "\u001da ^\u0001,\u0006",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "Recommended"-                                        ],-                                        "dlUri": "https:hvjrrbb"-                                    },-                                    "( > 4.6.5 && <= 3.3.5 ) || ( <= 4.1.2 && > 3.3.5 && == 2.4.1 && <= 4.2.1 && > 3.2.4 ) || ( == 1.3.3 && < 2.3.3 && > 1.2.2 && > 1.1.3 ) || ( < 1.2.1 && > 1.1.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "wcukj",-                                        "dlOutput": "􍨡|+s\u0006|",-                                        "dlSubdir": "𠒉􇄻BT",-                                        "dlTag": [],-                                        "dlUri": "http:zbyoega"-                                    },-                                    "( >= 5.4.5 )": {-                                        "dlCSize": 5,-                                        "dlHash": "",-                                        "dlOutput": "@T):-;",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "old",-                                            "old",-                                            "Latest",-                                            "Latest"-                                        ],-                                        "dlUri": "https:dbkp"-                                    }-                                }-                            },-                            "A_ARM64": {-                                "FreeBSD": {-                                    "( < 5.2.2 ) || ( >= 2.3.1 && < 4.3.3 && > 3.3.2 && < 4.1.1 && >= 2.4.4 && == 1.1.3 ) || ( <= 1.1.4 && > 1.3.2 && < 1.1.3 && <= 1.2.3 && >= 1.3.1 ) || ( >= 1.3.2 && > 1.1.1 && <= 2.1.2 && == 1.1.1 )": {-                                        "dlCSize": -5,-                                        "dlHash": "krzrt",-                                        "dlOutput": "􍲑𥵹i𡧳iG",-                                        "dlSubdir": "\u0017)󺒀|𭧬b",-                                        "dlTag": [-                                            "Nightly",-                                            "Experimental"-                                        ],-                                        "dlUri": "https:"-                                    },-                                    "( <= 4.3.2 && <= 5.4.1 && < 1.2.1 && <= 2.4.2 && >= 3.1.4 )": {-                                        "dlCSize": 4,-                                        "dlHash": "jwuw",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "@<x󻾀"-                                        },-                                        "dlTag": [-                                            "Latest",-                                            "old",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:r"-                                    },-                                    "( <= 5.1.5 && < 4.5.1 && < 2.5.3 && <= 5.3.5 ) || ( >= 4.4.4 && > 4.2.5 && >= 3.3.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "bxek",-                                        "dlOutput": "",-                                        "dlSubdir": "",-                                        "dlTag": null,-                                        "dlUri": "http:tiiv"-                                    },-                                    "( > 3.5.2 )": {-                                        "dlCSize": 1,-                                        "dlHash": "yxby",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "\u001d󰄪R %󿁣"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:mkio"-                                    },-                                    "( >= 1.2.4 && == 1.5.2 && > 4.5.2 && <= 2.3.2 )": {-                                        "dlCSize": 3,-                                        "dlHash": "mib",-                                        "dlOutput": "𰲘K\u0012-\\",-                                        "dlSubdir": {-                                            "RegexDir": "M𔕱GU"-                                        },-                                        "dlTag": [-                                            "LatestNightly",-                                            "Recommended",-                                            "Prerelease",-                                            "old",-                                            "LatestNightly",-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:szuqi"-                                    }-                                },-                                "Linux_Exherbo": {-                                    "( < 3.5.2 && <= 3.1.4 && > 1.1.3 && > 5.2.1 && == 4.5.1 )": {-                                        "dlCSize": 2,-                                        "dlHash": "vocuot",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "https:ncy"-                                    },-                                    "( < 4.5.3 && < 1.2.1 && >= 1.4.3 && < 1.1.6 && < 1.1.5 )": {-                                        "dlCSize": 4,-                                        "dlHash": "mcbypxg",-                                        "dlOutput": "6e3T\u000b\u0014",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-6.5.6",-                                            "VP\\o",-                                            "LatestPrerelease",-                                            "Latest",-                                            "old",-                                            "Latest",-                                            "base-4.3.3"-                                        ],-                                        "dlUri": "https:cnvgxq"-                                    },-                                    "( < 5.4.3 && <= 4.1.1 && >= 2.5.3 ) || ( == 1.1.4 && <= 2.4.3 && <= 4.1.2 )": {-                                        "dlCSize": -4,-                                        "dlHash": "oed",-                                        "dlOutput": "\tL",-                                        "dlSubdir": {-                                            "RegexDir": "8v7"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "Latest",-                                            "Nightly",-                                            "old",-                                            "LatestNightly",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:xcjc"-                                    },-                                    "( <= 2.2.3 && >= 2.3.2 && > 4.2.3 && >= 5.5.3 && >= 5.3.3 && <= 4.5.4 && > 1.5.1 )": {-                                        "dlCSize": -4,-                                        "dlHash": "z",-                                        "dlOutput": "G􍂇\u0014\u0003Z27",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:vtkh"-                                    },-                                    "( <= 5.4.1 && > 3.3.1 ) || ( <= 3.4.3 && < 1.2.5 && <= 4.2.4 && == 3.2.2 && >= 3.4.2 )": {-                                        "dlCSize": -6,-                                        "dlHash": "xvwqpc",-                                        "dlOutput": "Td5Wࣞh|",-                                        "dlSubdir": {-                                            "RegexDir": "{􋤠('"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "vheeqz",-                                        "dlOutput": "Op*",-                                        "dlSubdir": {-                                            "RegexDir": "j༫𒔾"-                                        },-                                        "dlTag": [-                                            "Latest",-                                            "Recommended",-                                            "LatestPrerelease",-                                            "",-                                            ""-                                        ],-                                        "dlUri": "https:do"-                                    }-                                },-                                "Linux_Rocky": {},-                                "Windows": {-                                    "( < 2.1.1 && >= 4.2.5 && >= 5.4.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "aktghf",-                                        "dlOutput": "k",-                                        "dlSubdir": "\u0003i\u0017M𬌖멸",-                                        "dlTag": [-                                            "Prerelease",-                                            "Latest",-                                            "Recommended",-                                            "Prerelease",-                                            "old",-                                            "B\u0006K+F"-                                        ],-                                        "dlUri": "http:xhaxda"-                                    },-                                    "( <= 1.4.1 && == 2.5.4 && > 6.4.5 && < 1.2.5 && > 1.3.1 && >= 2.1.2 ) || ( >= 2.2.2 && >= 4.3.4 && < 2.1.3 && > 1.4.3 && < 2.1.3 ) || ( <= 1.4.1 && > 2.2.1 && == 3.1.3 && > 1.3.1 ) || ( >= 2.2.1 )": {-                                        "dlCSize": 7,-                                        "dlHash": "oqa",-                                        "dlOutput": "􃱿WG\u0003b\u0003w",-                                        "dlSubdir": {-                                            "RegexDir": "󱑮9􇧔􃲕Wi"-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "Recommended",-                                            "a􆞑\u001c_"-                                        ],-                                        "dlUri": "https:bgbe"-                                    },-                                    "( <= 2.4.2 && < 4.5.3 && <= 2.3.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "eiyaikw",-                                        "dlOutput": null,-                                        "dlSubdir": "",-                                        "dlTag": null,-                                        "dlUri": "https:zncuow"-                                    },-                                    "( >= 2.5.5 && <= 4.5.3 && <= 5.5.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "porrmf",-                                        "dlOutput": "Q\u0007\\?𑵴;󶬈",-                                        "dlSubdir": {-                                            "RegexDir": "𝇦H󲈖𬉲"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:fo"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 4,-                                        "dlHash": "ms",-                                        "dlOutput": "%|",-                                        "dlSubdir": {-                                            "RegexDir": "󻿝6\u0016󼥑 "-                                        },-                                        "dlTag": null,-                                        "dlUri": "https:sai"-                                    }-                                }-                            },-                            "A_PowerPC64": {-                                "Darwin": {-                                    "( > 5.4.3 && == 3.5.2 && > 2.6.5 && <= 2.2.4 && <= 5.3.4 && >= 1.1.2 )": {-                                        "dlCSize": 6,-                                        "dlHash": "a",-                                        "dlOutput": null,-                                        "dlSubdir": "2",-                                        "dlTag": [-                                            "base-4.2.3",-                                            "Prerelease",-                                            "base-1.5.5",-                                            "Latest",-                                            "LatestPrerelease",-                                            "𠕯]7𡖑",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:tykzm"-                                    },-                                    "( >= 4.3.4 && > 3.1.2 && > 2.5.1 && >= 3.3.1 && > 3.5.4 && > 2.2.4 )": {-                                        "dlCSize": -3,-                                        "dlHash": "veyvaw",-                                        "dlOutput": "M\u0016󰎔󹌖A",-                                        "dlSubdir": {-                                            "RegexDir": "H𦷔􌹋\tjg"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:mdojj"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "qxxkys",-                                        "dlOutput": "\u0000h\rb\r#=",-                                        "dlSubdir": {-                                            "RegexDir": "`􂴸𣙈5\n𫔊"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "Latest",-                                            "Prerelease",-                                            "Recommended",-                                            "Prerelease",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "http:bcot"-                                    }-                                },-                                "FreeBSD": {-                                    "( == 1.4.1 && < 1.2.1 && > 5.6.1 && <= 1.1.1 && >= 2.5.2 ) || ( == 5.3.3 ) || ( < 3.1.3 && == 1.3.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "pgtz",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "O2\u0011\u001d\u0014"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:polgsx"-                                    },-                                    "( > 1.5.2 && <= 4.4.4 ) || ( == 3.3.4 && >= 1.3.4 && < 2.4.3 && <= 1.3.3 ) || ( <= 2.3.1 && < 3.1.2 )": {-                                        "dlCSize": -7,-                                        "dlHash": "qqh",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "䞖"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "LatestNightly",-                                            "base-4.1.1",-                                            "LatestPrerelease",-                                            "Experimental",-                                            "old"-                                        ],-                                        "dlUri": "https:ptmavu"-                                    }-                                },-                                "Linux_Mint": {},-                                "Linux_Ubuntu": {-                                    "( <= 1.1.4 ) || ( > 4.3.4 && > 4.3.2 && <= 1.2.3 && <= 3.2.1 ) || ( == 1.1.1 && > 1.2.3 && <= 3.1.2 && >= 2.4.1 ) || ( <= 2.3.2 && > 1.2.1 && > 1.2.1 ) || ( < 1.1.2 ) || ( >= 1.2.1 && <= 1.1.2 )": {-                                        "dlCSize": -6,-                                        "dlHash": "",-                                        "dlOutput": "sWR先rK",-                                        "dlSubdir": {-                                            "RegexDir": "4\u0016<"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "i"-                                        ],-                                        "dlUri": "http:"-                                    }-                                },-                                "Linux_Void": {-                                    "( < 2.2.5 && == 1.5.4 && >= 2.2.3 && > 3.5.4 && > 1.1.4 && >= 2.2.3 )": {-                                        "dlCSize": -2,-                                        "dlHash": "d",-                                        "dlOutput": "(\u0010㼍󷈨G",-                                        "dlSubdir": "6#`\u000e\u0013",-                                        "dlTag": [-                                            "Nightly",-                                            "Nightly",-                                            "LatestNightly",-                                            "Prerelease",-                                            "Recommended",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:jitcgfy"-                                    },-                                    "( <= 1.5.5 && < 3.5.3 && > 4.5.3 && > 5.3.5 && < 5.5.4 && > 5.2.2 ) || ( >= 4.2.2 && < 3.1.2 && > 1.4.1 && == 1.3.2 )": {-                                        "dlCSize": 4,-                                        "dlHash": "frzkdku",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "'xu'\n"-                                        },-                                        "dlTag": [-                                            "Experimental",-                                            "z𮇴#N"-                                        ],-                                        "dlUri": "https:evsgza"-                                    },-                                    "( == 4.1.1 && < 3.4.4 && <= 2.4.4 ) || ( < 4.1.1 && == 1.4.3 && >= 1.1.1 ) || ( == 2.3.1 && <= 1.2.1 && > 1.1.3 && == 1.3.3 )": {-                                        "dlCSize": 4,-                                        "dlHash": "",-                                        "dlOutput": "𒉭𪼙\u0018sZꯡg",-                                        "dlSubdir": {-                                            "RegexDir": "i\u0019sc7"-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "Prerelease",-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:adw"-                                    },-                                    "( > 2.5.1 ) || ( == 2.2.1 && >= 3.1.4 ) || ( < 3.1.3 )": {-                                        "dlCSize": -1,-                                        "dlHash": "ngdql",-                                        "dlOutput": null,-                                        "dlSubdir": "",-                                        "dlTag": null,-                                        "dlUri": "https:fwwdlec"-                                    },-                                    "( > 4.5.2 && >= 1.5.1 && > 5.2.1 && > 4.1.4 && > 4.2.5 && == 3.4.5 )": {-                                        "dlCSize": 0,-                                        "dlHash": "ajrbip",-                                        "dlOutput": "󼡕",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Latest",-                                            "Experimental",-                                            "base-3.1.6",-                                            "base-1.6.2",-                                            "Experimental",-                                            "Latest",-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:us"-                                    },-                                    "( > 5.4.3 && >= 1.2.3 && == 2.4.4 && < 3.1.1 ) || ( >= 2.1.4 ) || ( > 2.2.3 && < 2.3.2 && == 3.3.3 && < 2.5.2 && <= 3.1.2 ) || ( <= 1.2.1 && > 2.2.1 && > 2.1.2 && >= 2.1.2 )": {-                                        "dlCSize": -7,-                                        "dlHash": "qndhxzg",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-6.1.1",-                                            "Experimental",-                                            "Recommended"-                                        ],-                                        "dlUri": "http:qtm"-                                    },-                                    "( >= 4.3.3 && < 3.3.4 && > 2.1.3 && < 4.1.4 && > 1.1.2 && > 3.3.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "g",-                                        "dlOutput": "\u0003#{𪲛d6",-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "LatestPrerelease"-                                        ],-                                        "dlUri": "https:wlsutzk"-                                    }-                                },-                                "Windows": {-                                    "( < 3.4.3 && < 3.4.2 && < 1.4.4 && >= 5.5.3 )": {-                                        "dlCSize": null,-                                        "dlHash": "",-                                        "dlOutput": null,-                                        "dlSubdir": "",-                                        "dlTag": null,-                                        "dlUri": "https:tc"-                                    },-                                    "( <= 5.5.4 && < 4.4.1 && < 1.1.3 && >= 4.2.4 && <= 6.5.4 )": {-                                        "dlCSize": -7,-                                        "dlHash": "ejvhn",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Latest",-                                            "LatestNightly",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:bl"-                                    },-                                    "( == 3.3.4 ) || ( < 2.1.4 && == 3.3.4 && < 1.3.3 && < 3.1.3 ) || ( < 1.2.1 && > 2.1.2 && == 1.1.1 && <= 3.2.2 && == 1.3.2 )": {-                                        "dlCSize": -7,-                                        "dlHash": "wutxg",-                                        "dlOutput": "\n",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Experimental",-                                            "LatestNightly",-                                            "LatestNightly",-                                            "Experimental",-                                            "𓇶\u000e",-                                            "Recommended",-                                            "Latest"-                                        ],-                                        "dlUri": "https:pncfaik"-                                    },-                                    "( >= 2.4.4 && > 1.4.4 && <= 5.5.4 && == 3.4.4 ) || ( == 4.4.2 && <= 4.3.2 && > 1.4.4 && >= 2.4.1 && == 3.1.4 && <= 1.4.4 ) || ( <= 1.1.2 )": {-                                        "dlCSize": 7,-                                        "dlHash": "d",-                                        "dlOutput": "?iKg",-                                        "dlSubdir": {-                                            "RegexDir": "\u0005"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:rcpl"-                                    },-                                    "( >= 2.5.5 && == 3.3.3 && > 2.5.2 )": {-                                        "dlCSize": 2,-                                        "dlHash": "pokyjmt",-                                        "dlOutput": null,-                                        "dlSubdir": "+e驪ncu",-                                        "dlTag": null,-                                        "dlUri": "http:orndago"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 7,-                                        "dlHash": "aoejxxh",-                                        "dlOutput": "",-                                        "dlSubdir": "",-                                        "dlTag": [-                                            "Latest",-                                            "LatestNightly",-                                            "Latest",-                                            "base-2.6.5",-                                            "LatestPrerelease",-                                            "LatestPrerelease",-                                            "\u0016h#\u0004"-                                        ],-                                        "dlUri": "http:egno"-                                    }-                                }-                            },-                            "A_Sparc": {-                                "Darwin": {-                                    "( < 3.2.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "vdmtw",-                                        "dlOutput": "O𑻯𐽿i(6",-                                        "dlSubdir": "r^",-                                        "dlTag": [-                                            "Latest",-                                            "base-5.2.3",-                                            "Experimental",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:c"-                                    },-                                    "( < 5.2.2 && == 3.2.4 && <= 5.4.3 && < 4.2.4 && == 3.4.2 && > 1.1.5 )": {-                                        "dlCSize": 0,-                                        "dlHash": "i",-                                        "dlOutput": "M.B\\",-                                        "dlSubdir": {-                                            "RegexDir": "𤝜󺡆𧟕\u000c􌰟\u0011"-                                        },-                                        "dlTag": [],-                                        "dlUri": "http:dmdr"-                                    },-                                    "( <= 2.2.3 && > 4.3.3 )": {-                                        "dlCSize": -3,-                                        "dlHash": "jl",-                                        "dlOutput": "",-                                        "dlSubdir": "|\u0015X>0",-                                        "dlTag": null,-                                        "dlUri": "https:oemfq"-                                    },-                                    "( <= 4.4.3 && == 2.1.1 && == 1.1.2 && > 5.1.2 )": {-                                        "dlCSize": null,-                                        "dlHash": "ihzncbv",-                                        "dlOutput": "𢉈2eM",-                                        "dlSubdir": "\u000b",-                                        "dlTag": [-                                            "Prerelease"-                                        ],-                                        "dlUri": "https:cpdba"-                                    },-                                    "( <= 5.3.2 && == 1.2.3 && < 3.3.5 ) || ( <= 2.5.4 && < 4.4.2 && > 3.3.4 && < 4.4.3 && <= 3.3.3 && == 3.2.1 )": {-                                        "dlCSize": -3,-                                        "dlHash": "wpdnjb",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": [],-                                        "dlUri": "https:lwz"-                                    },-                                    "( > 1.4.5 )": {-                                        "dlCSize": 7,-                                        "dlHash": "hqsiy",-                                        "dlOutput": "󷩼y\\F犮",-                                        "dlSubdir": "F\u0014`",-                                        "dlTag": [],-                                        "dlUri": "https:"-                                    },-                                    "( > 2.5.3 && < 4.5.2 && < 2.2.2 ) || ( >= 3.2.5 && > 5.1.3 && < 4.3.4 && > 1.1.3 )": {-                                        "dlCSize": 4,-                                        "dlHash": "d",-                                        "dlOutput": null,-                                        "dlSubdir": "F;\"",-                                        "dlTag": null,-                                        "dlUri": "https:f"-                                    }-                                },-                                "FreeBSD": {-                                    "( > 5.2.3 ) || ( == 3.3.3 && > 4.4.2 && > 1.4.1 && >= 4.3.1 && <= 4.1.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "skb",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Nightly",-                                            "base-2.5.3"-                                        ],-                                        "dlUri": "http:azhh"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 1,-                                        "dlHash": "vtonjw",-                                        "dlOutput": "",-                                        "dlSubdir": "􄈗^",-                                        "dlTag": [-                                            "old"-                                        ],-                                        "dlUri": "https:lduyxm"-                                    }-                                },-                                "Linux_Mint": {-                                    "( <= 2.2.2 && <= 3.3.4 && >= 5.4.3 && >= 2.5.2 && > 4.2.4 && < 3.1.2 && >= 3.4.1 )": {-                                        "dlCSize": -7,-                                        "dlHash": "fj",-                                        "dlOutput": "\u0004V𦐹/",-                                        "dlSubdir": {-                                            "RegexDir": "󿆘􈈱"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "Nightly"-                                        ],-                                        "dlUri": "https:ergibm"-                                    },-                                    "( == 2.2.5 && < 3.4.2 && > 3.5.3 ) || ( == 3.3.4 && > 1.3.1 && >= 2.2.1 && <= 3.2.2 && >= 4.1.2 )": {-                                        "dlCSize": 2,-                                        "dlHash": "b",-                                        "dlOutput": "?",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "LatestPrerelease",-                                            ""-                                        ],-                                        "dlUri": "https:uyvaxil"-                                    },-                                    "( == 2.5.5 && <= 1.3.5 && >= 2.4.3 && == 1.5.3 && <= 3.3.1 && >= 4.1.3 ) || ( == 2.2.4 && <= 4.3.1 && == 4.3.3 && >= 1.4.4 ) || ( <= 3.3.3 && >= 3.1.2 && >= 3.1.1 && > 3.1.3 && <= 2.3.2 ) || ( <= 3.1.1 && >= 2.2.1 ) || ( < 2.1.2 )": {-                                        "dlCSize": -7,-                                        "dlHash": "am",-                                        "dlOutput": "\t)w",-                                        "dlSubdir": {-                                            "RegexDir": "\u000e"-                                        },-                                        "dlTag": [-                                            "Prerelease"-                                        ],-                                        "dlUri": "http:jompdr"-                                    },-                                    "( == 5.2.5 && < 1.2.2 ) || ( > 1.3.2 && <= 1.3.2 && < 1.4.1 ) || ( <= 2.3.3 ) || ( <= 2.2.2 && <= 1.4.2 && >= 2.1.1 && > 3.2.2 )": {-                                        "dlCSize": -4,-                                        "dlHash": "u",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "\u0006wM\u0018"-                                        },-                                        "dlTag": [-                                            "Nightly",-                                            "old",-                                            "old",-                                            "Latest"-                                        ],-                                        "dlUri": "https:ihmzk"-                                    },-                                    "( > 4.5.5 && < 5.1.4 && >= 4.4.1 && == 2.5.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "vluz",-                                        "dlOutput": "\u001dEd14",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "Experimental",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:ybvls"-                                    },-                                    "( >= 2.4.5 && < 2.4.5 )": {-                                        "dlCSize": null,-                                        "dlHash": "vv",-                                        "dlOutput": "",-                                        "dlSubdir": {-                                            "RegexDir": "!􋉾K7"-                                        },-                                        "dlTag": [-                                            "Recommended",-                                            "Latest",-                                            "Prerelease",-                                            "Experimental",-                                            "Prerelease",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:qqeii"-                                    },-                                    "( >= 5.4.3 && > 3.2.4 && >= 5.3.2 ) || ( >= 3.3.1 && > 1.4.4 && == 4.3.3 && <= 2.1.1 && < 3.4.1 ) || ( < 2.2.1 && < 3.1.3 && <= 1.3.2 && < 3.3.3 && <= 1.2.1 )": {-                                        "dlCSize": -4,-                                        "dlHash": "xx",-                                        "dlOutput": "B󼷂􄚌􁃃mG",-                                        "dlSubdir": {-                                            "RegexDir": "`󼠝쐭%"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:dm"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": null,-                                        "dlHash": "k",-                                        "dlOutput": "􄏶𡲘󰹳",-                                        "dlSubdir": {-                                            "RegexDir": "\u0003O𮞊yN"-                                        },-                                        "dlTag": [-                                            "base-6.2.3",-                                            "Nightly",-                                            "old",-                                            "old",-                                            "Recommended",-                                            "Experimental"-                                        ],-                                        "dlUri": "http:frteyk"-                                    }-                                },-                                "Linux_UnknownLinux": {-                                    "( < 2.1.5 && > 4.3.5 && >= 4.3.3 && >= 2.5.3 && > 2.5.1 && > 3.2.3 && >= 4.2.1 )": {-                                        "dlCSize": -6,-                                        "dlHash": "jioim",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-6.5.2",-                                            "Latest"-                                        ],-                                        "dlUri": "http:br"-                                    },-                                    "( <= 2.2.1 ) || ( <= 1.3.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "rbm",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [],-                                        "dlUri": "https:prnsi"-                                    },-                                    "( <= 2.3.5 && <= 2.2.5 && == 2.3.2 && >= 3.3.3 && == 3.4.2 ) || ( <= 4.3.4 && == 4.4.4 )": {-                                        "dlCSize": -2,-                                        "dlHash": "hhgpqko",-                                        "dlOutput": null,-                                        "dlSubdir": "/󳃿\\",-                                        "dlTag": [-                                            "old"-                                        ],-                                        "dlUri": "http:imq"-                                    },-                                    "( == 2.4.5 ) || ( > 4.2.1 && < 2.2.1 ) || ( > 1.3.4 && < 2.1.3 && > 4.3.2 && <= 3.2.2 && >= 3.3.2 )": {-                                        "dlCSize": -1,-                                        "dlHash": "r",-                                        "dlOutput": "A𨭐a󠅦",-                                        "dlSubdir": {-                                            "RegexDir": "𢧋\u0005B\nh"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "j[",-                                            "LatestNightly"-                                        ],-                                        "dlUri": "https:dapuity"-                                    },-                                    "( >= 1.3.1 && >= 1.2.4 )": {-                                        "dlCSize": 6,-                                        "dlHash": "wtvy",-                                        "dlOutput": null,-                                        "dlSubdir": null,-                                        "dlTag": null,-                                        "dlUri": "http:u"-                                    },-                                    "( >= 2.4.1 && >= 1.5.3 && <= 1.5.4 && > 3.3.4 && <= 2.5.4 )": {-                                        "dlCSize": null,-                                        "dlHash": "lvjr",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": "󿙈<;"-                                        },-                                        "dlTag": [-                                            "LatestPrerelease",-                                            "LatestPrerelease",-                                            "LatestNightly",-                                            "Nightly",-                                            "base-2.2.1",-                                            "",-                                            "*Jg𡜳\u0019"-                                        ],-                                        "dlUri": "https:xwtxrk"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": 5,-                                        "dlHash": "z",-                                        "dlOutput": null,-                                        "dlSubdir": {-                                            "RegexDir": ""-                                        },-                                        "dlTag": [-                                            "Prerelease",-                                            "Prerelease",-                                            "old",-                                            "Nightly",-                                            "LatestNightly",-                                            "Nightly"-                                        ],-                                        "dlUri": "http:"-                                    }-                                },-                                "Windows": {-                                    "( == 1.3.1 && <= 5.5.1 && >= 1.1.4 && < 2.5.4 && <= 4.1.1 && <= 5.5.1 && == 5.3.1 )": {-                                        "dlCSize": null,-                                        "dlHash": "fkdtts",-                                        "dlOutput": "\u000f\u0006XB",-                                        "dlSubdir": {-                                            "RegexDir": "<\u0003q\u0008\u0002"-                                        },-                                        "dlTag": null,-                                        "dlUri": "http:pwniy"-                                    },-                                    "( > 2.4.2 && > 2.4.5 && < 4.1.4 && <= 1.3.1 && > 1.4.1 ) || ( > 3.2.3 && >= 2.4.1 && > 4.3.2 && > 3.3.5 && > 3.4.1 && < 3.3.3 ) || ( >= 1.2.3 && > 3.2.2 && == 3.1.2 && > 1.1.1 )": {-                                        "dlCSize": 3,-                                        "dlHash": "",-                                        "dlOutput": "",-                                        "dlSubdir": null,-                                        "dlTag": [-                                            "base-4.3.1"-                                        ],-                                        "dlUri": "http:axrww"-                                    },-                                    "unknown_versioning": {-                                        "dlCSize": -2,-                                        "dlHash": "vbijgk",-                                        "dlOutput": "\u001d祐F1𗪗PT",-                                        "dlSubdir": "\u00133\u0016k[~",-                                        "dlTag": null,-                                        "dlUri": "http:ycnh"-                                    }-                                }-                            }-                        },-                        "viChangeLog": "https:jvo",-                        "viPostInstall": "zdmmgqv",-                        "viPostRemove": null,-                        "viPreCompile": "ws",-                        "viPreInstall": "ukoevy",-                        "viReleaseDay": "3938621829868156-10-26",-                        "viSourceDL": {-                            "dlCSize": -3,-                            "dlHash": "ie",-                            "dlOutput": "\u001e;g]\ra",-                            "dlSubdir": {-                                "RegexDir": "󵰦q𤀒B"-                            },-                            "dlTag": null,-                            "dlUri": "http:fnzea"-                        },-                        "viTags": [-                            "base-2.4.6",-                            "old",-                            "base-4.3.5"-                        ],-                        "viTestDL": {-                            "dlCSize": -5,-                            "dlHash": "abl",-                            "dlOutput": "\u0019)",-                            "dlSubdir": null,-                            "dlTag": [-                                "Recommended",-                                "Latest",-                                "LatestPrerelease",-                                "Prerelease",-                                "Nightly",-                                "old"-                            ],-                            "dlUri": "http:bp"-                        }-                    }-                }-            },-            "metadataUpdate": "https:",-            "toolRequirements": {-                "Cabal": {-                    "1.2.4": {-                        "FreeBSD": {-                            "( <= 4.1.5 && == 1.2.5 && <= 2.4.4 && > 2.1.5 ) || ( >= 3.2.4 )": {-                                "distroPKGs": [-                                    "xzkibnx"-                                ],-                                "notes": "m"-                            },-                            "( == 2.2.4 && >= 1.2.5 && >= 3.5.4 && > 4.4.3 && <= 1.4.2 && == 4.5.4 && > 4.4.5 ) || ( > 4.4.3 ) || ( <= 3.2.1 && == 4.3.1 && >= 2.2.2 && < 1.1.3 ) || ( == 2.2.1 && < 2.3.2 && <= 1.1.1 ) || ( > 1.1.1 && <= 1.1.2 )": {-                                "distroPKGs": [-                                    "b",-                                    "",-                                    "o",-                                    "p",-                                    "ucrr",-                                    "uq",-                                    "nboecb"-                                ],-                                "notes": "ty"-                            },-                            "( == 3.2.1 && >= 5.3.3 && <= 4.4.2 && == 1.1.3 && == 1.3.5 ) || ( >= 1.2.3 && > 4.1.4 && < 5.2.1 && < 1.4.3 && <= 2.3.3 && <= 4.1.1 )": {-                                "distroPKGs": [-                                    "tzjiwy",-                                    "aodupc",-                                    "",-                                    "jffq"-                                ],-                                "notes": "gfupb"-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "",-                                    "zy",-                                    "pbol",-                                    "gwfj",-                                    "j"-                                ],-                                "notes": "prdes"-                            }-                        }-                    },-                    "1.5.1": {},-                    "1.6.4": {-                        "Darwin": {-                            "( <= 2.5.1 && >= 1.5.1 && >= 3.1.4 && == 3.2.6 && > 4.3.2 && == 2.3.2 )": {-                                "distroPKGs": [],-                                "notes": "q"-                            },-                            "( == 5.2.4 ) || ( < 3.4.4 && > 4.3.2 && < 3.4.1 ) || ( > 1.3.3 ) || ( < 1.1.2 && <= 2.2.1 && > 1.2.1 ) || ( == 1.1.2 && < 1.2.1 && > 1.1.1 )": {-                                "distroPKGs": [-                                    "mkzmajq",-                                    "enyyzyl",-                                    "qsvpg",-                                    ""-                                ],-                                "notes": "mhfomak"-                            },-                            "( > 4.3.4 )": {-                                "distroPKGs": [-                                    "lseqj",-                                    "fnx",-                                    "bdnjz",-                                    "wqxp",-                                    "ybictp",-                                    "w",-                                    "awi"-                                ],-                                "notes": "undim"-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "yi",-                                    "umlwl",-                                    "",-                                    "",-                                    "rf",-                                    "drzem",-                                    "k"-                                ],-                                "notes": "ppzga"-                            }-                        },-                        "Linux_Alpine": {-                            "( == 3.5.5 && >= 2.1.5 && == 5.4.3 )": {-                                "distroPKGs": [],-                                "notes": "jbs"-                            },-                            "( > 2.1.5 && <= 3.5.5 && <= 5.2.5 && >= 5.2.3 && < 3.4.2 && >= 2.1.3 )": {-                                "distroPKGs": [],-                                "notes": "nnedp"-                            },-                            "( >= 1.4.3 && <= 4.2.4 && <= 1.3.4 && == 3.2.2 && > 2.2.3 ) || ( >= 4.2.1 && <= 1.1.3 && > 4.1.2 && == 2.3.4 && < 2.4.4 && == 1.4.1 ) || ( == 2.1.2 && == 2.1.1 && == 1.1.3 && == 3.4.2 && >= 3.2.1 ) || ( > 2.2.2 && > 2.1.2 ) || ( >= 1.1.2 ) || ( == 2.1.2 && < 1.1.1 ) || ( < 2.2.1 )": {-                                "distroPKGs": [-                                    "shku",-                                    "tdjojbs",-                                    "",-                                    "iibq",-                                    "rwnhpqz",-                                    "rph"-                                ],-                                "notes": "hlz"-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "lkrdee",-                                    ""-                                ],-                                "notes": "fps"-                            }-                        },-                        "Windows": {-                            "( < 1.2.2 && <= 1.4.2 && > 4.4.3 && == 4.1.2 && >= 1.1.3 && < 4.5.4 ) || ( > 3.4.2 && > 2.1.1 && > 1.3.2 )": {-                                "distroPKGs": [],-                                "notes": "ohnkoz"-                            },-                            "( == 1.1.1 ) || ( > 4.2.2 )": {-                                "distroPKGs": [-                                    "mpkf",-                                    "bom",-                                    "ntoikd",-                                    "q",-                                    "co",-                                    "xuux",-                                    "txwij"-                                ],-                                "notes": "gt"-                            },-                            "( == 4.4.3 ) || ( >= 3.3.3 && >= 1.4.3 && < 1.2.1 && >= 1.1.3 && == 1.4.1 && > 3.2.2 )": {-                                "distroPKGs": [-                                    "kuqpubm",-                                    "to"-                                ],-                                "notes": "etdwdl"-                            },-                            "( == 4.5.1 ) || ( > 1.1.1 && <= 3.1.1 && < 4.4.2 && > 2.4.1 && <= 4.2.1 && <= 2.4.4 )": {-                                "distroPKGs": [-                                    "aonsj",-                                    "qit",-                                    "ppaie"-                                ],-                                "notes": "di"-                            },-                            "( > 1.2.1 && < 4.4.4 && < 1.1.1 && >= 2.1.1 && <= 3.3.1 && == 5.5.1 && < 4.4.4 )": {-                                "distroPKGs": [],-                                "notes": "hmlk"-                            },-                            "( > 4.1.5 && >= 4.5.3 )": {-                                "distroPKGs": [-                                    "gg",-                                    "tdsxhi",-                                    "anzukv",-                                    "mxxvk",-                                    "peutsaw",-                                    "sd"-                                ],-                                "notes": "bc"-                            },-                            "( >= 1.1.2 && < 3.1.1 && <= 5.5.4 && > 1.3.2 && == 4.2.3 && == 5.1.5 && < 3.4.4 )": {-                                "distroPKGs": [-                                    "suvz",-                                    "a",-                                    "cm"-                                ],-                                "notes": ""-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "",-                                    "zceo",-                                    "grnalj",-                                    "igrlf"-                                ],-                                "notes": "ypzv"-                            }-                        }-                    },-                    "4.3.5": {-                        "Darwin": {-                            "( >= 1.5.4 && > 2.4.5 && <= 4.3.2 && > 1.3.5 && == 5.2.2 && <= 1.5.4 ) || ( == 4.4.1 && < 2.1.2 ) || ( > 2.1.1 && >= 3.3.2 && <= 3.1.3 && <= 3.1.2 && == 3.2.3 )": {-                                "distroPKGs": [-                                    "",-                                    "t",-                                    "gr",-                                    "",-                                    "x",-                                    "lj",-                                    "cq"-                                ],-                                "notes": "btsw"-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "jciqb"-                                ],-                                "notes": "p"-                            }-                        },-                        "Windows": {}-                    },-                    "5.8.7": {},-                    "6.6.3": {-                        "Darwin": {-                            "( < 3.2.1 && < 3.3.5 && == 4.2.5 && <= 2.2.4 && <= 1.3.3 ) || ( == 3.2.3 && < 3.2.1 && > 3.1.3 && > 3.2.2 && <= 1.2.2 && == 1.4.2 ) || ( >= 2.3.2 && <= 2.1.3 ) || ( > 1.2.2 && >= 3.1.2 && <= 2.1.2 )": {-                                "distroPKGs": [-                                    "t",-                                    "fiunji"-                                ],-                                "notes": "iyh"-                            },-                            "( < 5.4.1 && > 2.1.1 ) || ( >= 3.3.2 && > 2.3.2 && == 2.1.4 && > 3.4.3 && == 1.3.4 && < 3.3.3 )": {-                                "distroPKGs": [-                                    "",-                                    "dqj",-                                    "kcgiy"-                                ],-                                "notes": "wgnn"-                            },-                            "( == 1.1.4 && == 3.4.3 )": {-                                "distroPKGs": [-                                    "qcxal",-                                    "gss",-                                    "sqs",-                                    "zajv"-                                ],-                                "notes": "vf"-                            },-                            "( == 4.4.1 && >= 1.4.4 )": {-                                "distroPKGs": [-                                    "oxma",-                                    "og",-                                    "",-                                    "xqzwod",-                                    "dydy",-                                    "vlyxz"-                                ],-                                "notes": "d"-                            },-                            "( == 5.4.2 ) || ( < 1.4.3 && == 4.1.1 ) || ( > 2.1.2 )": {-                                "distroPKGs": [-                                    "z",-                                    "k",-                                    "wi"-                                ],-                                "notes": "yzixmsk"-                            },-                            "( >= 4.4.2 )": {-                                "distroPKGs": [],-                                "notes": "ixgw"-                            },-                            "unknown_versioning": {-                                "distroPKGs": [-                                    "tie",-                                    "epfzlll",-                                    "nmlc",-                                    "gnqy",-                                    "",-                                    ""-                                ],-                                "notes": "h"-                            }-                        },-                        "FreeBSD": {},-                        "Linux_Mint": {-                            "( < 5.5.4 && >= 3.1.1 && < 5.4.4 && < 3.5.5 ) || ( > 3.3.1 && < 1.4.5 && < 2.4.4 && == 3.2.1 )": {-                                "distroPKGs": [-                                    "yhtyyrz"-                                ],-                                "notes": ""-                            },-                            "( > 3.2.2 && > 5.3.2 ) || ( >= 3.2.4 && == 2.1.1 && == 4.6.1 && < 2.4.2 && > 4.4.2 )": {-                                "distroPKGs": [-                                    "ywvthv",-                                    "ualffo",-                                    "p",-                                    "ivxxrh",-                                    "xig",-                                    "b"-                                ],-                                "notes": ""-                            }-                        }-                    },-                    "unknown_version": {}-                }-            }-        }-    ],-    "seed": 821709850+                "\u001d;\u0005y": {+                    "toolDetails": null,+                    "toolVersions": {+                        "1.1.1": {+                            "changelog": "https:",+                            "postInstall": null,+                            "postRemove": "",+                            "preCompile": "",+                            "preInstall": "",+                            "releaseDay": "-8791569164896357-04-08",+                            "revisionSpec": {},+                            "tags": []+                        },+                        "2.1.1": {+                            "changelog": "http:",+                            "postInstall": "",+                            "postRemove": "",+                            "preCompile": "",+                            "preInstall": "",+                            "releaseDay": null,+                            "revisionSpec": {},+                            "tags": []+                        },+                        "3.3.2": {+                            "changelog": "http:",+                            "postInstall": "",+                            "postRemove": "",+                            "preCompile": null,+                            "preInstall": null,+                            "releaseDay": "17435268342960108-04-12",+                            "revisionSpec": {},+                            "tags": []+                        }+                    }+                },+                "(l": {+                    "toolDetails": {+                        "toolAuthor": "",+                        "toolContact": "",+                        "toolDescription": "",+                        "toolHomepage": "http:",+                        "toolLicense": "",+                        "toolMaintainer": "",+                        "toolRepository": "http:"+                    },+                    "toolVersions": {+                        "1.1.3": {+                            "changelog": "https:",+                            "postInstall": null,+                            "postRemove": "",+                            "preCompile": "",+                            "preInstall": "",+                            "releaseDay": "-20399206759176242-07-10",+                            "revisionSpec": {},+                            "tags": []+                        }+                    }+                },+                "6": {+                    "toolDetails": {+                        "toolAuthor": "",+                        "toolContact": "",+                        "toolDescription": "",+                        "toolHomepage": "https:",+                        "toolLicense": "",+                        "toolMaintainer": "",+                        "toolRepository": null+                    },+                    "toolVersions": {}+                },+                "spo\u0000\u001a": {+                    "toolDetails": {+                        "toolAuthor": "",+                        "toolContact": "",+                        "toolDescription": "",+                        "toolHomepage": "https:",+                        "toolLicense": "",+                        "toolMaintainer": "",+                        "toolRepository": "https:"+                    },+                    "toolVersions": {}+                },+                "z\u0001x6\n": {+                    "toolDetails": {+                        "toolAuthor": "",+                        "toolContact": "",+                        "toolDescription": "",+                        "toolHomepage": "http:",+                        "toolLicense": "",+                        "toolMaintainer": "",+                        "toolRepository": null+                    },+                    "toolVersions": {}+                }+            },+            "metadataUpdate": "http:sy",+            "toolRequirements": {+                ",\u0013\u0000y": {},+                "6<": {+                    "4.4.5": {+                        "Darwin": {+                            "( < 1.1.1 ) || ( == 1.2.1 && <= 1.1.1 )": {+                                "distroPKGs": [+                                    "qb",+                                    "",+                                    "cjm",+                                    "xen"+                                ],+                                "notes": ""+                            },+                            "( < 1.2.1 && < 2.2.2 && == 2.1.1 && > 1.1.3 )": {+                                "distroPKGs": [+                                    "ikg",+                                    "q"+                                ],+                                "notes": "ub"+                            },+                            "( < 2.2.2 )": {+                                "distroPKGs": [+                                    "y",+                                    ""+                                ],+                                "notes": ""+                            },+                            "( <= 2.1.1 && < 1.1.1 && == 1.2.1 && >= 2.2.2 )": {+                                "distroPKGs": [+                                    "ctnp",+                                    "r"+                                ],+                                "notes": "vp"+                            },+                            "( == 1.1.1 ) || ( > 1.1.2 ) || ( == 2.1.1 )": {+                                "distroPKGs": [+                                    "r",+                                    ""+                                ],+                                "notes": ""+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "eg",+                                    "c",+                                    ""+                                ],+                                "notes": ""+                            }+                        },+                        "FreeBSD": {+                            "( <= 1.1.1 )": {+                                "distroPKGs": [+                                    "ynjo"+                                ],+                                "notes": ""+                            },+                            "( == 1.1.1 ) || ( <= 1.1.1 ) || ( <= 1.2.1 ) || ( < 2.1.2 )": {+                                "distroPKGs": [+                                    "lcaq"+                                ],+                                "notes": "uzmt"+                            },+                            "( >= 1.2.1 && <= 1.2.2 && < 1.1.1 ) || ( == 1.2.1 )": {+                                "distroPKGs": [+                                    "azs",+                                    "zt"+                                ],+                                "notes": "zwtf"+                            },+                            "( >= 1.2.1 && >= 1.2.1 ) || ( == 1.2.1 && < 1.1.1 )": {+                                "distroPKGs": [+                                    "dzqb",+                                    "g"+                                ],+                                "notes": "bp"+                            },+                            "( >= 1.2.2 && <= 1.2.3 && < 2.2.1 && < 2.1.2 )": {+                                "distroPKGs": [+                                    "h",+                                    "oc",+                                    "wf"+                                ],+                                "notes": "no"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "dlu",+                                    "",+                                    "b"+                                ],+                                "notes": "ypvr"+                            }+                        },+                        "OpenBSD": {+                            "( <= 1.1.1 && >= 1.1.2 && < 1.1.1 ) || ( > 1.1.2 ) || ( >= 2.2.1 ) || ( <= 1.1.2 )": {+                                "distroPKGs": [+                                    "pcb",+                                    "fni",+                                    ""+                                ],+                                "notes": "gvwv"+                            },+                            "( == 1.1.1 ) || ( < 1.1.2 ) || ( <= 1.1.1 )": {+                                "distroPKGs": [+                                    "pxo",+                                    "o",+                                    "ar",+                                    "r"+                                ],+                                "notes": "wdy"+                            },+                            "( == 2.2.1 && > 1.1.1 && < 1.1.1 ) || ( == 1.1.2 )": {+                                "distroPKGs": [+                                    "hd"+                                ],+                                "notes": "on"+                            }+                        },+                        "Windows": {+                            "( < 1.1.2 ) || ( >= 1.1.1 && == 1.1.1 ) || ( >= 1.2.1 )": {+                                "distroPKGs": [+                                    "y"+                                ],+                                "notes": "rcwa"+                            },+                            "( < 2.1.1 && <= 1.1.1 ) || ( >= 1.2.1 ) || ( <= 1.1.1 ) || ( > 1.1.1 )": {+                                "distroPKGs": [],+                                "notes": "v"+                            },+                            "( > 1.1.1 && == 1.1.2 && < 2.1.1 ) || ( < 2.1.1 ) || ( > 1.1.1 )": {+                                "distroPKGs": [+                                    "",+                                    "",+                                    ""+                                ],+                                "notes": "lzkb"+                            },+                            "( > 2.2.1 && == 1.3.1 )": {+                                "distroPKGs": [+                                    "toay",+                                    "kafy"+                                ],+                                "notes": "h"+                            },+                            "( >= 1.2.1 && <= 2.2.2 && <= 1.1.2 && == 2.1.2 )": {+                                "distroPKGs": [+                                    "pq",+                                    "gwu"+                                ],+                                "notes": "dv"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "v"+                                ],+                                "notes": "avri"+                            }+                        }+                    },+                    "6.5.1": {},+                    "6.7.2": {+                        "FreeBSD": {+                            "( > 1.1.2 && < 1.1.1 && <= 1.1.2 ) || ( >= 1.1.1 ) || ( == 1.2.1 ) || ( > 1.1.1 )": {+                                "distroPKGs": [+                                    "i",+                                    ""+                                ],+                                "notes": "jv"+                            },+                            "( > 2.2.1 && > 1.1.1 && == 1.1.1 )": {+                                "distroPKGs": [+                                    "unze",+                                    "",+                                    "qckn",+                                    "u"+                                ],+                                "notes": "i"+                            }+                        },+                        "Linux_Gentoo": {},+                        "OpenBSD": {+                            "unknown_versioning": {+                                "distroPKGs": [],+                                "notes": ""+                            }+                        },+                        "Windows": {}+                    },+                    "8.3.2": {+                        "Linux_Fedora": {},+                        "Windows": {+                            "( < 1.2.2 && > 1.1.1 && <= 2.2.1 && == 2.1.1 )": {+                                "distroPKGs": [],+                                "notes": "wwfg"+                            },+                            "( <= 1.1.1 && < 1.1.1 ) || ( < 2.1.2 && >= 1.1.1 )": {+                                "distroPKGs": [+                                    "waps",+                                    "mto"+                                ],+                                "notes": "wll"+                            },+                            "( <= 1.2.2 && > 2.1.1 && <= 1.2.1 && <= 2.2.1 )": {+                                "distroPKGs": [+                                    "vbfb"+                                ],+                                "notes": "wta"+                            },+                            "( <= 2.1.1 && >= 1.1.2 && <= 2.4.2 )": {+                                "distroPKGs": [+                                    "tr",+                                    "ue",+                                    "",+                                    ""+                                ],+                                "notes": "td"+                            },+                            "( == 1.2.2 ) || ( <= 1.1.1 ) || ( > 1.1.1 )": {+                                "distroPKGs": [+                                    "",+                                    ""+                                ],+                                "notes": ""+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "",+                                    "x",+                                    "kz",+                                    ""+                                ],+                                "notes": "dvm"+                            }+                        }+                    },+                    "unknown_version": {}+                },+                "p\u0006@": {+                    "3.8.7": {+                        "FreeBSD": {+                            "( <= 1.1.1 && < 1.2.1 ) || ( < 1.1.1 )": {+                                "distroPKGs": [+                                    "",+                                    "",+                                    "er",+                                    "xn"+                                ],+                                "notes": "hqjd"+                            },+                            "( > 1.1.1 && > 1.1.1 ) || ( == 1.1.1 ) || ( < 1.2.1 )": {+                                "distroPKGs": [],+                                "notes": "ef"+                            },+                            "( > 1.1.1 ) || ( == 1.2.2 && > 2.1.1 )": {+                                "distroPKGs": [+                                    "",+                                    "ykmj",+                                    "fx"+                                ],+                                "notes": "xy"+                            }+                        },+                        "OpenBSD": {+                            "( < 2.2.1 && <= 1.1.1 ) || ( > 1.1.1 && <= 1.1.1 ) || ( < 2.1.1 )": {+                                "distroPKGs": [],+                                "notes": "tca"+                            },+                            "( == 2.1.1 && > 2.2.1 && <= 2.2.1 )": {+                                "distroPKGs": [],+                                "notes": "fobc"+                            },+                            "( > 1.1.2 )": {+                                "distroPKGs": [+                                    "oau"+                                ],+                                "notes": "la"+                            },+                            "( > 2.1.2 && <= 1.2.2 )": {+                                "distroPKGs": [+                                    "wctr",+                                    "s",+                                    "tiyo",+                                    "qrw"+                                ],+                                "notes": ""+                            },+                            "( >= 1.2.2 )": {+                                "distroPKGs": [+                                    "kzre",+                                    "",+                                    "d",+                                    "rh"+                                ],+                                "notes": "fbrk"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "wpzu",+                                    "",+                                    "yl"+                                ],+                                "notes": "gi"+                            }+                        },+                        "Windows": {+                            "( <= 1.1.1 ) || ( <= 1.1.2 ) || ( >= 1.1.2 ) || ( >= 1.1.1 )": {+                                "distroPKGs": [+                                    "",+                                    "sv"+                                ],+                                "notes": "jb"+                            },+                            "( <= 2.1.1 ) || ( > 2.2.1 )": {+                                "distroPKGs": [+                                    "ifqe",+                                    "xhju"+                                ],+                                "notes": "rav"+                            },+                            "( == 2.1.2 )": {+                                "distroPKGs": [+                                    "jbym",+                                    "axqs"+                                ],+                                "notes": "clm"+                            },+                            "( > 1.2.1 && == 2.2.2 && > 2.1.1 && == 1.1.1 )": {+                                "distroPKGs": [],+                                "notes": "xg"+                            },+                            "( > 1.2.2 && > 1.1.3 && >= 2.1.1 )": {+                                "distroPKGs": [+                                    "xusc",+                                    "gis",+                                    "hxhg",+                                    "zw"+                                ],+                                "notes": "f"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "zqar",+                                    "y",+                                    "slr"+                                ],+                                "notes": "a"+                            }+                        }+                    },+                    "4.2.7": {+                        "FreeBSD": {+                            "( <= 1.1.1 && <= 1.1.1 && <= 2.1.1 ) || ( == 2.1.1 && > 1.1.1 )": {+                                "distroPKGs": [+                                    "od",+                                    "kwu",+                                    "u"+                                ],+                                "notes": "vmr"+                            },+                            "( >= 1.1.1 && <= 1.2.1 ) || ( == 2.2.1 && >= 1.1.1 )": {+                                "distroPKGs": [],+                                "notes": "qh"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "rp",+                                    "ov",+                                    "",+                                    "vgw"+                                ],+                                "notes": "ezsz"+                            }+                        },+                        "Linux_Debian": {+                            "( < 1.1.1 && == 1.1.1 && >= 2.1.1 ) || ( < 1.1.1 && == 1.1.1 ) || ( < 2.2.1 )": {+                                "distroPKGs": [],+                                "notes": "ara"+                            },+                            "( <= 1.1.1 ) || ( >= 1.1.1 )": {+                                "distroPKGs": [+                                    "qrdj",+                                    "dqgn"+                                ],+                                "notes": "q"+                            },+                            "( == 1.1.1 && == 1.2.1 ) || ( == 1.1.2 ) || ( == 1.1.1 )": {+                                "distroPKGs": [+                                    "",+                                    "dax",+                                    "",+                                    "bg"+                                ],+                                "notes": "rr"+                            },+                            "( >= 2.2.1 && > 1.1.2 && >= 1.2.2 && >= 1.1.1 )": {+                                "distroPKGs": [+                                    "x"+                                ],+                                "notes": "u"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "q",+                                    "hxbs",+                                    "ktos",+                                    "ealq"+                                ],+                                "notes": "ca"+                            }+                        },+                        "Linux_Exherbo": {+                            "( == 1.1.1 ) || ( < 1.1.2 && == 1.1.1 )": {+                                "distroPKGs": [+                                    "cbq",+                                    "uirl",+                                    "a"+                                ],+                                "notes": "rgkl"+                            },+                            "( == 1.1.1 ) || ( > 2.1.1 )": {+                                "distroPKGs": [+                                    "xdcb"+                                ],+                                "notes": "ho"+                            },+                            "( > 1.1.1 && <= 2.1.1 && <= 1.2.2 ) || ( <= 1.1.1 )": {+                                "distroPKGs": [+                                    "kine"+                                ],+                                "notes": "h"+                            },+                            "( > 1.2.2 )": {+                                "distroPKGs": [+                                    "kd",+                                    "wksy"+                                ],+                                "notes": "sfq"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "cee",+                                    "m",+                                    "jt",+                                    "uxd"+                                ],+                                "notes": ""+                            }+                        },+                        "Linux_Ubuntu": {+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "nglj",+                                    "a"+                                ],+                                "notes": "ln"+                            }+                        }+                    },+                    "7.6.5": {+                        "Darwin": {+                            "( < 1.1.2 && < 1.1.2 && == 1.2.2 ) || ( >= 1.1.1 )": {+                                "distroPKGs": [+                                    "xdhh",+                                    "gxq"+                                ],+                                "notes": "qene"+                            },+                            "( > 1.1.1 ) || ( <= 1.1.1 && > 1.1.2 )": {+                                "distroPKGs": [],+                                "notes": "sgl"+                            },+                            "( > 1.2.2 && == 1.1.1 && > 1.1.1 ) || ( > 1.2.1 ) || ( > 1.1.2 ) || ( == 1.2.2 )": {+                                "distroPKGs": [+                                    "aixd",+                                    "",+                                    "hyw",+                                    "bpb"+                                ],+                                "notes": ""+                            },+                            "( > 4.2.2 && > 1.2.2 && >= 2.1.2 )": {+                                "distroPKGs": [+                                    "q",+                                    "mw",+                                    ""+                                ],+                                "notes": "qg"+                            },+                            "( >= 1.1.1 && < 2.1.1 ) || ( >= 1.1.1 )": {+                                "distroPKGs": [+                                    "jfv",+                                    "tzkz",+                                    "goi",+                                    "eb"+                                ],+                                "notes": "kdp"+                            },+                            "( >= 1.1.1 ) || ( == 1.2.1 ) || ( == 1.1.1 )": {+                                "distroPKGs": [+                                    "mnac",+                                    "ixd",+                                    "oc"+                                ],+                                "notes": "pvsb"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "",+                                    "n",+                                    "n"+                                ],+                                "notes": "wct"+                            }+                        },+                        "FreeBSD": {+                            "( < 2.2.2 && > 1.2.2 && >= 2.2.3 && == 2.1.2 )": {+                                "distroPKGs": [+                                    "s"+                                ],+                                "notes": ""+                            },+                            "( <= 2.1.2 && > 2.1.2 )": {+                                "distroPKGs": [+                                    "b",+                                    "rmf",+                                    "cghz"+                                ],+                                "notes": ""+                            },+                            "( >= 1.1.1 && < 1.1.1 && == 2.1.1 ) || ( == 1.1.1 && < 1.1.1 ) || ( > 1.1.2 )": {+                                "distroPKGs": [+                                    "g"+                                ],+                                "notes": "hl"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "mbid",+                                    "qz",+                                    "q",+                                    "dnc"+                                ],+                                "notes": ""+                            }+                        },+                        "Linux_Exherbo": {+                            "( < 1.1.1 && < 1.1.1 ) || ( == 1.2.1 ) || ( <= 2.1.1 ) || ( > 1.1.1 )": {+                                "distroPKGs": [+                                    "oia",+                                    ""+                                ],+                                "notes": "jky"+                            },+                            "( < 1.1.1 && == 2.1.2 ) || ( == 1.2.1 ) || ( >= 1.1.1 ) || ( <= 1.1.1 )": {+                                "distroPKGs": [],+                                "notes": ""+                            },+                            "( <= 1.2.2 )": {+                                "distroPKGs": [+                                    ""+                                ],+                                "notes": "j"+                            },+                            "( <= 2.2.1 )": {+                                "distroPKGs": [+                                    "k",+                                    "hdid",+                                    "zdvh",+                                    "mx"+                                ],+                                "notes": "o"+                            },+                            "( > 2.1.2 && < 1.1.2 && < 2.1.1 )": {+                                "distroPKGs": [],+                                "notes": "f"+                            },+                            "( >= 2.1.1 && == 1.1.2 && < 1.2.1 ) || ( > 1.1.1 && <= 2.1.1 ) || ( < 1.1.1 )": {+                                "distroPKGs": [],+                                "notes": "erau"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "dz",+                                    "pv",+                                    "c",+                                    ""+                                ],+                                "notes": "azh"+                            }+                        },+                        "Windows": {+                            "( < 2.2.2 )": {+                                "distroPKGs": [+                                    "",+                                    ""+                                ],+                                "notes": "bkk"+                            },+                            "( == 2.1.1 && >= 2.2.2 )": {+                                "distroPKGs": [+                                    "dax",+                                    "t",+                                    "dobh"+                                ],+                                "notes": "d"+                            },+                            "( > 1.3.2 && == 1.2.3 )": {+                                "distroPKGs": [+                                    "b"+                                ],+                                "notes": "h"+                            }+                        }+                    },+                    "8.5.7": {+                        "Darwin": {+                            "( == 1.1.1 && > 1.2.1 && <= 2.1.1 ) || ( >= 1.1.1 && > 1.1.1 ) || ( <= 1.1.1 )": {+                                "distroPKGs": [+                                    "kk",+                                    "qbou",+                                    "hzey",+                                    "d"+                                ],+                                "notes": "ow"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [],+                                "notes": "it"+                            }+                        },+                        "Linux_Debian": {+                            "( == 1.1.1 && <= 1.1.2 && >= 1.1.1 ) || ( >= 1.1.1 && <= 1.1.1 )": {+                                "distroPKGs": [+                                    "ag"+                                ],+                                "notes": ""+                            }+                        },+                        "Linux_RedHat": {+                            "( == 1.1.1 ) || ( >= 1.1.1 && > 2.1.1 ) || ( <= 1.1.1 )": {+                                "distroPKGs": [+                                    "ifad",+                                    "isj",+                                    "e",+                                    "yp"+                                ],+                                "notes": "xw"+                            }+                        },+                        "OpenBSD": {},+                        "Windows": {+                            "( < 1.2.2 && >= 1.1.1 ) || ( >= 1.1.1 ) || ( <= 2.2.1 ) || ( <= 1.1.2 )": {+                                "distroPKGs": [+                                    "scaw",+                                    "jr"+                                ],+                                "notes": "tb"+                            },+                            "( <= 1.1.1 ) || ( <= 1.1.1 && < 1.1.1 )": {+                                "distroPKGs": [+                                    "zweb",+                                    "fjpp",+                                    "x",+                                    "pl"+                                ],+                                "notes": "pq"+                            },+                            "( == 1.2.2 && > 1.1.1 && == 1.1.2 && < 1.1.1 )": {+                                "distroPKGs": [+                                    "vm"+                                ],+                                "notes": "dx"+                            },+                            "( == 2.2.1 && >= 2.1.1 )": {+                                "distroPKGs": [+                                    "bqpc",+                                    "s",+                                    "tbdo",+                                    ""+                                ],+                                "notes": "cfcg"+                            },+                            "( >= 1.1.1 && > 1.1.2 && >= 1.1.1 ) || ( < 1.1.1 && == 1.1.1 )": {+                                "distroPKGs": [],+                                "notes": "bj"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [],+                                "notes": "j"+                            }+                        }+                    }+                }+            }+        },+        {+            "ghcupDownloads": {+                "4": {+                    "toolDetails": {+                        "toolAuthor": "",+                        "toolContact": "",+                        "toolDescription": "",+                        "toolHomepage": "https:",+                        "toolLicense": "",+                        "toolMaintainer": "",+                        "toolRepository": null+                    },+                    "toolVersions": {}+                },+                "g`\u0006anf": {+                    "toolDetails": {+                        "toolAuthor": "",+                        "toolContact": "",+                        "toolDescription": "",+                        "toolHomepage": "http:",+                        "toolLicense": "",+                        "toolMaintainer": "",+                        "toolRepository": "http:"+                    },+                    "toolVersions": {+                        "2.2.2": {+                            "changelog": null,+                            "postInstall": "",+                            "postRemove": "",+                            "preCompile": "",+                            "preInstall": "",+                            "releaseDay": "-21696335035624399-06-28",+                            "revisionSpec": {},+                            "tags": []+                        }+                    }+                },+                "k": {+                    "toolDetails": {+                        "toolAuthor": null,+                        "toolContact": null,+                        "toolDescription": "",+                        "toolHomepage": "http:",+                        "toolLicense": null,+                        "toolMaintainer": null,+                        "toolRepository": "http:"+                    },+                    "toolVersions": {+                        "1.3.3": {+                            "changelog": "https:",+                            "postInstall": "",+                            "postRemove": null,+                            "preCompile": null,+                            "preInstall": "",+                            "releaseDay": "-18865655703723805-07-27",+                            "revisionSpec": {},+                            "tags": []+                        },+                        "3.1.2": {+                            "changelog": "http:",+                            "postInstall": "",+                            "postRemove": null,+                            "preCompile": "",+                            "preInstall": null,+                            "releaseDay": "10366089730599605-06-20",+                            "revisionSpec": {},+                            "tags": []+                        }+                    }+                },+                "n?": {+                    "toolDetails": {+                        "toolAuthor": "",+                        "toolContact": "",+                        "toolDescription": "",+                        "toolHomepage": null,+                        "toolLicense": "",+                        "toolMaintainer": "",+                        "toolRepository": "http:"+                    },+                    "toolVersions": {+                        "1.3.1": {+                            "changelog": "https:",+                            "postInstall": "",+                            "postRemove": "",+                            "preCompile": "",+                            "preInstall": null,+                            "releaseDay": "6344031471043112-04-29",+                            "revisionSpec": {},+                            "tags": []+                        },+                        "2.3.1": {+                            "changelog": null,+                            "postInstall": null,+                            "postRemove": "",+                            "preCompile": "",+                            "preInstall": "",+                            "releaseDay": "5360518418508929-11-03",+                            "revisionSpec": {},+                            "tags": []+                        },+                        "3.2.3": {+                            "changelog": null,+                            "postInstall": "",+                            "postRemove": "",+                            "preCompile": "",+                            "preInstall": null,+                            "releaseDay": "-5593712519057301-10-10",+                            "revisionSpec": {},+                            "tags": []+                        }+                    }+                },+                "v[r": {+                    "toolDetails": {+                        "toolAuthor": "",+                        "toolContact": "",+                        "toolDescription": "",+                        "toolHomepage": "https:",+                        "toolLicense": "",+                        "toolMaintainer": "",+                        "toolRepository": "https:"+                    },+                    "toolVersions": {+                        "2.1.2": {+                            "changelog": "https:",+                            "postInstall": "",+                            "postRemove": "",+                            "preCompile": "",+                            "preInstall": "",+                            "releaseDay": "-9262895168850227-07-18",+                            "revisionSpec": {},+                            "tags": []+                        },+                        "2.2.1": {+                            "changelog": "https:",+                            "postInstall": "",+                            "postRemove": "",+                            "preCompile": "",+                            "preInstall": "",+                            "releaseDay": "-24619781721787646-04-30",+                            "revisionSpec": {},+                            "tags": []+                        },+                        "5.2.3": {+                            "changelog": "https:",+                            "postInstall": "",+                            "postRemove": null,+                            "preCompile": "",+                            "preInstall": null,+                            "releaseDay": null,+                            "revisionSpec": {},+                            "tags": []+                        }+                    }+                },+                "vv3s\u001c": {+                    "toolDetails": {+                        "toolAuthor": "",+                        "toolContact": null,+                        "toolDescription": "",+                        "toolHomepage": "http:",+                        "toolLicense": null,+                        "toolMaintainer": "",+                        "toolRepository": "https:"+                    },+                    "toolVersions": {+                        "1.3.3": {+                            "changelog": "https:",+                            "postInstall": null,+                            "postRemove": "",+                            "preCompile": "",+                            "preInstall": "",+                            "releaseDay": null,+                            "revisionSpec": {},+                            "tags": []+                        }+                    }+                }+            },+            "metadataUpdate": "http:",+            "toolRequirements": {+                "\u0003\u0006qia5_": {+                    "3.4.5": {+                        "Darwin": {+                            "( <= 1.1.1 && > 1.1.1 && < 1.2.1 ) || ( > 1.1.1 )": {+                                "distroPKGs": [+                                    "tad"+                                ],+                                "notes": ""+                            },+                            "( > 1.1.1 && == 1.1.1 ) || ( <= 1.1.1 && > 1.1.1 ) || ( > 1.1.1 )": {+                                "distroPKGs": [+                                    "",+                                    "kdh",+                                    "h",+                                    "mizt"+                                ],+                                "notes": "jp"+                            },+                            "( > 1.1.2 && < 2.1.2 && == 1.2.1 && <= 3.1.1 )": {+                                "distroPKGs": [+                                    "f",+                                    "",+                                    "c",+                                    "ma"+                                ],+                                "notes": "sz"+                            },+                            "( >= 1.1.1 && <= 2.1.1 ) || ( <= 1.1.1 )": {+                                "distroPKGs": [+                                    "",+                                    "pdeq"+                                ],+                                "notes": "dthe"+                            },+                            "( >= 2.1.1 ) || ( > 1.1.2 ) || ( <= 1.1.1 ) || ( < 2.1.1 )": {+                                "distroPKGs": [],+                                "notes": ""+                            },+                            "unknown_versioning": {+                                "distroPKGs": [],+                                "notes": "w"+                            }+                        },+                        "Linux_UnknownLinux": {+                            "( < 2.1.2 && == 2.1.2 && < 1.2.3 && == 2.2.3 )": {+                                "distroPKGs": [],+                                "notes": ""+                            },+                            "( <= 1.1.1 ) || ( < 2.1.2 && > 1.2.1 )": {+                                "distroPKGs": [+                                    "b",+                                    "nh",+                                    "au",+                                    "uy"+                                ],+                                "notes": "z"+                            },+                            "( <= 1.2.2 && == 3.1.2 )": {+                                "distroPKGs": [],+                                "notes": "zue"+                            },+                            "( <= 2.1.2 && < 1.1.1 && >= 1.1.2 && > 2.1.2 )": {+                                "distroPKGs": [+                                    "",+                                    "w",+                                    "re",+                                    "mg"+                                ],+                                "notes": "miqk"+                            },+                            "( == 1.1.1 && < 1.1.1 ) || ( >= 2.1.1 ) || ( <= 2.1.1 ) || ( > 1.1.2 )": {+                                "distroPKGs": [+                                    "zp"+                                ],+                                "notes": "poxy"+                            },+                            "( == 1.1.1 ) || ( >= 1.1.1 ) || ( < 1.1.1 ) || ( == 1.1.1 )": {+                                "distroPKGs": [+                                    "kbr",+                                    "iki"+                                ],+                                "notes": "z"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "n",+                                    ""+                                ],+                                "notes": "oqz"+                            }+                        },+                        "OpenBSD": {+                            "( < 2.2.1 && < 2.1.1 && <= 1.2.2 )": {+                                "distroPKGs": [+                                    "",+                                    "ab",+                                    "qbq"+                                ],+                                "notes": ""+                            },+                            "( == 1.2.1 && < 2.2.2 && <= 3.3.1 )": {+                                "distroPKGs": [],+                                "notes": "v"+                            },+                            "( > 1.1.1 && >= 2.1.2 && == 2.2.1 && == 2.1.3 )": {+                                "distroPKGs": [+                                    "d",+                                    ""+                                ],+                                "notes": "zkuu"+                            },+                            "( >= 1.1.1 && > 1.1.1 && == 1.1.1 ) || ( >= 1.1.2 )": {+                                "distroPKGs": [+                                    "tych",+                                    ""+                                ],+                                "notes": "wta"+                            }+                        }+                    },+                    "8.1.5": {+                        "Darwin": {+                            "( < 1.1.2 && >= 1.1.1 && <= 1.1.1 ) || ( <= 1.2.1 && <= 1.1.1 ) || ( == 1.1.2 ) || ( == 2.1.2 )": {+                                "distroPKGs": [+                                    "wm",+                                    "ut",+                                    "ab",+                                    "zs"+                                ],+                                "notes": "l"+                            },+                            "( < 1.2.2 && >= 1.1.2 && <= 1.1.2 && <= 2.1.2 )": {+                                "distroPKGs": [+                                    "jtav",+                                    "",+                                    "r",+                                    "y"+                                ],+                                "notes": "ursf"+                            },+                            "( > 1.1.2 && <= 1.1.1 ) || ( < 1.1.1 && >= 1.1.1 ) || ( <= 2.1.1 )": {+                                "distroPKGs": [+                                    "",+                                    "k",+                                    "ddg"+                                ],+                                "notes": "oae"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [],+                                "notes": "a"+                            }+                        },+                        "OpenBSD": {+                            "( == 1.2.2 )": {+                                "distroPKGs": [+                                    "oywn",+                                    "cec"+                                ],+                                "notes": ""+                            },+                            "( > 2.1.2 && <= 2.2.1 )": {+                                "distroPKGs": [+                                    "nyar",+                                    "fax",+                                    "jic"+                                ],+                                "notes": ""+                            },+                            "( >= 2.2.1 && < 1.1.1 )": {+                                "distroPKGs": [],+                                "notes": "dd"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "eor",+                                    "dw"+                                ],+                                "notes": ""+                            }+                        },+                        "Windows": {+                            "( < 2.1.1 && <= 2.2.1 && > 2.1.1 )": {+                                "distroPKGs": [+                                    "pu",+                                    "k",+                                    "",+                                    "o"+                                ],+                                "notes": "mac"+                            },+                            "( < 2.1.4 && == 2.1.1 && >= 3.2.1 )": {+                                "distroPKGs": [+                                    "dc",+                                    "r",+                                    "twsi",+                                    "p"+                                ],+                                "notes": ""+                            },+                            "( <= 1.1.1 ) || ( < 1.1.1 && >= 1.1.1 )": {+                                "distroPKGs": [+                                    "qk",+                                    "",+                                    ""+                                ],+                                "notes": "my"+                            },+                            "( <= 2.2.2 && >= 2.1.1 )": {+                                "distroPKGs": [+                                    "rcw",+                                    "",+                                    "mtzb",+                                    "a"+                                ],+                                "notes": "kqwg"+                            },+                            "( <= 3.2.3 && > 2.1.1 )": {+                                "distroPKGs": [+                                    "ny"+                                ],+                                "notes": "w"+                            },+                            "( == 2.1.3 )": {+                                "distroPKGs": [],+                                "notes": "hnp"+                            },+                            "( >= 1.2.1 && < 2.1.1 ) || ( > 1.1.1 ) || ( >= 1.1.1 ) || ( > 1.1.1 )": {+                                "distroPKGs": [+                                    "",+                                    "pl"+                                ],+                                "notes": "ugjq"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "qj",+                                    "o"+                                ],+                                "notes": "h"+                            }+                        }+                    },+                    "8.5.8": {+                        "Darwin": {+                            "( < 1.1.1 && < 1.1.2 && <= 1.1.1 ) || ( == 1.3.1 ) || ( <= 1.1.1 )": {+                                "distroPKGs": [+                                    "l",+                                    "",+                                    "lyl"+                                ],+                                "notes": "g"+                            },+                            "( < 1.1.2 ) || ( > 1.1.1 && > 2.1.1 )": {+                                "distroPKGs": [+                                    "",+                                    "x",+                                    "rntu",+                                    "od"+                                ],+                                "notes": "txwe"+                            },+                            "( > 2.2.2 && < 2.2.2 && > 2.2.1 && > 1.3.2 )": {+                                "distroPKGs": [+                                    "znl",+                                    "",+                                    "cvql"+                                ],+                                "notes": ""+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "ecey",+                                    "j",+                                    "",+                                    "ndhy"+                                ],+                                "notes": "mem"+                            }+                        },+                        "OpenBSD": {+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "tiy",+                                    "hah",+                                    "rifw",+                                    "jnwo"+                                ],+                                "notes": "uvl"+                            }+                        },+                        "Windows": {+                            "( == 1.1.1 ) || ( > 1.1.1 && <= 1.1.2 )": {+                                "distroPKGs": [+                                    "g",+                                    "zquk",+                                    "",+                                    "hrfo"+                                ],+                                "notes": "gtvz"+                            },+                            "( == 1.2.1 ) || ( >= 1.1.1 )": {+                                "distroPKGs": [+                                    "wdv"+                                ],+                                "notes": "ozip"+                            },+                            "( > 1.1.1 && == 1.1.2 && >= 1.1.1 ) || ( > 1.1.1 ) || ( > 2.1.1 )": {+                                "distroPKGs": [+                                    "da"+                                ],+                                "notes": "wk"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "jz",+                                    "q",+                                    "rcie",+                                    "zsq"+                                ],+                                "notes": "yov"+                            }+                        }+                    }+                },+                ">)ex1": {+                    "2.1.7": {+                        "Darwin": {+                            "( < 2.1.1 && >= 1.2.3 && <= 2.2.2 )": {+                                "distroPKGs": [],+                                "notes": "d"+                            },+                            "( <= 2.2.2 )": {+                                "distroPKGs": [],+                                "notes": "hbo"+                            },+                            "( == 1.1.2 && <= 1.2.1 && < 2.1.1 && <= 3.2.1 )": {+                                "distroPKGs": [],+                                "notes": ""+                            },+                            "( == 1.1.2 && > 2.2.3 )": {+                                "distroPKGs": [],+                                "notes": "in"+                            },+                            "( == 2.1.1 )": {+                                "distroPKGs": [],+                                "notes": "dtyb"+                            },+                            "( > 1.1.2 ) || ( <= 1.2.1 && <= 1.1.1 ) || ( == 1.2.1 ) || ( > 1.1.2 )": {+                                "distroPKGs": [],+                                "notes": "i"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [],+                                "notes": "at"+                            }+                        },+                        "FreeBSD": {+                            "( > 1.2.1 && > 1.1.2 && >= 1.1.1 ) || ( < 1.1.1 ) || ( > 1.1.1 )": {+                                "distroPKGs": [],+                                "notes": ""+                            },+                            "( > 1.3.1 && < 1.2.3 )": {+                                "distroPKGs": [+                                    "mf"+                                ],+                                "notes": "nb"+                            },+                            "( > 2.2.2 )": {+                                "distroPKGs": [+                                    "oph"+                                ],+                                "notes": "j"+                            },+                            "( >= 2.2.2 && > 2.2.1 && < 2.2.1 )": {+                                "distroPKGs": [],+                                "notes": ""+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "krcg",+                                    ""+                                ],+                                "notes": "r"+                            }+                        },+                        "Linux_RedHat": {+                            "( <= 1.1.1 && <= 1.1.1 && < 1.1.2 ) || ( == 1.1.2 && >= 1.1.1 ) || ( >= 2.1.1 )": {+                                "distroPKGs": [+                                    "cyp"+                                ],+                                "notes": "oqi"+                            },+                            "( <= 1.2.1 ) || ( >= 2.1.1 && <= 1.1.2 )": {+                                "distroPKGs": [+                                    "nx",+                                    "cv",+                                    "yo",+                                    "to"+                                ],+                                "notes": "tu"+                            },+                            "( == 2.1.1 && < 2.1.1 && < 1.1.2 && > 2.1.2 )": {+                                "distroPKGs": [],+                                "notes": ""+                            },+                            "( == 2.1.2 && >= 1.3.1 )": {+                                "distroPKGs": [+                                    "h"+                                ],+                                "notes": ""+                            },+                            "( == 2.2.3 && == 3.1.2 && >= 2.1.2 && == 1.2.2 )": {+                                "distroPKGs": [+                                    "lmi",+                                    "pb",+                                    "ulve"+                                ],+                                "notes": "dtnh"+                            },+                            "( > 2.1.2 && > 2.3.2 )": {+                                "distroPKGs": [+                                    "edko"+                                ],+                                "notes": ""+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "pri"+                                ],+                                "notes": "mim"+                            }+                        },+                        "OpenBSD": {+                            "( <= 1.1.1 && > 1.1.1 && >= 1.1.1 ) || ( > 1.1.1 && < 1.1.1 )": {+                                "distroPKGs": [+                                    "e",+                                    "rhsm",+                                    "ecbc"+                                ],+                                "notes": "jj"+                            },+                            "( <= 1.2.2 && == 1.1.1 && == 1.1.2 )": {+                                "distroPKGs": [+                                    "wzl"+                                ],+                                "notes": "xo"+                            },+                            "( > 1.1.2 && < 2.2.2 && <= 2.2.1 && == 1.1.2 )": {+                                "distroPKGs": [+                                    "dr",+                                    ""+                                ],+                                "notes": "l"+                            },+                            "( >= 1.1.1 && < 1.1.1 )": {+                                "distroPKGs": [+                                    "x",+                                    "x",+                                    ""+                                ],+                                "notes": "nloo"+                            },+                            "( >= 1.1.2 && < 2.1.2 && >= 1.1.1 && > 1.2.2 )": {+                                "distroPKGs": [+                                    "ysnq"+                                ],+                                "notes": "idw"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "klx"+                                ],+                                "notes": "r"+                            }+                        }+                    },+                    "3.2.5": {+                        "FreeBSD": {+                            "( == 3.1.2 )": {+                                "distroPKGs": [+                                    "",+                                    "g",+                                    "dkx"+                                ],+                                "notes": "mhag"+                            },+                            "( >= 1.1.1 ) || ( == 1.1.1 && < 1.1.1 )": {+                                "distroPKGs": [+                                    "hx",+                                    "ko"+                                ],+                                "notes": "wt"+                            }+                        },+                        "Linux_Gentoo": {+                            "( < 1.1.1 && < 1.1.2 ) || ( <= 1.1.1 )": {+                                "distroPKGs": [+                                    "zkw",+                                    "ahu",+                                    "o"+                                ],+                                "notes": "z"+                            },+                            "( == 2.2.2 && <= 2.2.2 && == 2.3.2 && >= 1.1.2 )": {+                                "distroPKGs": [+                                    "fxu",+                                    "z",+                                    "jgdz",+                                    "bdvl"+                                ],+                                "notes": "dac"+                            },+                            "( > 1.1.1 ) || ( > 1.1.1 && <= 1.1.1 )": {+                                "distroPKGs": [+                                    "mpkh",+                                    "okz",+                                    "scw",+                                    "oqa"+                                ],+                                "notes": "xrgy"+                            },+                            "( > 1.2.1 && < 1.1.1 && <= 1.1.1 ) || ( >= 2.1.1 )": {+                                "distroPKGs": [+                                    "aivo"+                                ],+                                "notes": "usr"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "",+                                    "",+                                    "c",+                                    "yzh"+                                ],+                                "notes": "fo"+                            }+                        },+                        "OpenBSD": {+                            "( == 1.1.2 )": {+                                "distroPKGs": [+                                    "",+                                    "gnww",+                                    "t",+                                    "ddr"+                                ],+                                "notes": "m"+                            },+                            "( > 1.1.2 ) || ( < 1.1.1 )": {+                                "distroPKGs": [+                                    "vxz"+                                ],+                                "notes": ""+                            },+                            "( > 1.2.1 && < 1.1.1 ) || ( >= 1.2.2 && <= 1.1.2 )": {+                                "distroPKGs": [+                                    "lbzz",+                                    "nwhg",+                                    "poqx",+                                    "av"+                                ],+                                "notes": "mrfh"+                            },+                            "( >= 2.3.1 && <= 2.1.2 && == 2.1.1 && == 2.1.2 )": {+                                "distroPKGs": [+                                    "",+                                    "bl",+                                    "yrf"+                                ],+                                "notes": "cxf"+                            }+                        }+                    },+                    "3.5.1": {+                        "FreeBSD": {+                            "( < 1.1.1 && >= 1.1.2 && > 1.1.2 && >= 1.2.2 )": {+                                "distroPKGs": [],+                                "notes": "k"+                            },+                            "( < 1.1.2 && <= 1.2.2 ) || ( <= 1.1.1 && >= 1.1.1 )": {+                                "distroPKGs": [+                                    "",+                                    "gz",+                                    "",+                                    "z"+                                ],+                                "notes": ""+                            },+                            "( < 1.2.1 && > 1.1.1 && == 1.1.3 )": {+                                "distroPKGs": [+                                    "jcn",+                                    "",+                                    "tthr",+                                    "qk"+                                ],+                                "notes": "pmb"+                            },+                            "( <= 1.1.1 && >= 2.1.1 ) || ( == 1.1.1 && >= 1.2.1 ) || ( < 2.2.1 ) || ( < 2.1.1 )": {+                                "distroPKGs": [+                                    "kqx"+                                ],+                                "notes": "sh"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "ee"+                                ],+                                "notes": "j"+                            }+                        },+                        "Linux_Alpine": {+                            "( < 1.1.2 ) || ( >= 1.1.1 ) || ( >= 2.1.2 )": {+                                "distroPKGs": [],+                                "notes": "q"+                            },+                            "( < 2.1.2 ) || ( < 1.1.1 ) || ( > 1.2.1 )": {+                                "distroPKGs": [+                                    "else",+                                    "ra",+                                    "a"+                                ],+                                "notes": "x"+                            },+                            "( <= 1.2.1 ) || ( >= 1.2.1 )": {+                                "distroPKGs": [+                                    "pml"+                                ],+                                "notes": "tjt"+                            },+                            "( <= 2.2.2 && < 2.1.1 )": {+                                "distroPKGs": [+                                    "ax",+                                    "",+                                    "li",+                                    "dl"+                                ],+                                "notes": "f"+                            },+                            "( == 2.2.2 && <= 1.3.2 )": {+                                "distroPKGs": [+                                    "airx"+                                ],+                                "notes": "y"+                            },+                            "( == 2.2.2 && > 3.2.4 && < 1.4.2 )": {+                                "distroPKGs": [+                                    "fc",+                                    "x",+                                    "",+                                    "opl"+                                ],+                                "notes": "l"+                            },+                            "( >= 2.2.2 && >= 2.2.3 )": {+                                "distroPKGs": [+                                    "av",+                                    "rac",+                                    "j",+                                    ""+                                ],+                                "notes": "yyc"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    ""+                                ],+                                "notes": "va"+                            }+                        },+                        "Linux_Rocky": {+                            "( < 2.2.1 && == 2.3.2 && == 1.1.1 && < 2.1.2 )": {+                                "distroPKGs": [+                                    "v"+                                ],+                                "notes": "cu"+                            },+                            "( <= 1.1.1 ) || ( > 1.1.1 )": {+                                "distroPKGs": [+                                    "",+                                    "d",+                                    "f"+                                ],+                                "notes": "wwg"+                            },+                            "( <= 3.2.1 )": {+                                "distroPKGs": [+                                    "ms",+                                    "p",+                                    "tngt",+                                    ""+                                ],+                                "notes": "so"+                            },+                            "( == 1.1.2 && >= 2.1.1 && <= 1.1.1 ) || ( < 2.1.1 && < 1.1.1 ) || ( >= 1.2.1 ) || ( < 1.1.1 )": {+                                "distroPKGs": [+                                    "k",+                                    "ogri",+                                    "rg",+                                    "bilt"+                                ],+                                "notes": "bi"+                            },+                            "( == 1.2.1 && <= 2.1.2 )": {+                                "distroPKGs": [+                                    "c",+                                    "tsp"+                                ],+                                "notes": "phac"+                            },+                            "( >= 1.2.2 )": {+                                "distroPKGs": [+                                    "jhc",+                                    "lus",+                                    "w"+                                ],+                                "notes": "ai"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "r",+                                    "z",+                                    "tcz"+                                ],+                                "notes": "mov"+                            }+                        },+                        "Linux_UnknownLinux": {},+                        "OpenBSD": {+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "h",+                                    "fa",+                                    "k"+                                ],+                                "notes": "gc"+                            }+                        },+                        "Windows": {}+                    },+                    "4.6.1": {+                        "Darwin": {+                            "( <= 3.2.2 && < 1.1.1 && < 2.1.2 )": {+                                "distroPKGs": [+                                    "zepu",+                                    "hewj",+                                    "bkpn"+                                ],+                                "notes": ""+                            },+                            "( >= 1.1.1 && < 2.1.1 ) || ( == 1.1.1 && > 1.1.1 )": {+                                "distroPKGs": [+                                    "",+                                    ""+                                ],+                                "notes": "zh"+                            },+                            "( >= 1.2.1 ) || ( < 1.2.2 )": {+                                "distroPKGs": [+                                    "qbm"+                                ],+                                "notes": "kre"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "eb"+                                ],+                                "notes": "egb"+                            }+                        },+                        "OpenBSD": {+                            "unknown_versioning": {+                                "distroPKGs": [+                                    ""+                                ],+                                "notes": "zcl"+                            }+                        }+                    },+                    "6.3.4": {+                        "Darwin": {+                            "( == 1.3.2 )": {+                                "distroPKGs": [+                                    "ee",+                                    "shu",+                                    ""+                                ],+                                "notes": "xrwu"+                            },+                            "( == 2.1.2 && < 2.2.2 && >= 1.2.1 && >= 1.1.2 )": {+                                "distroPKGs": [+                                    ""+                                ],+                                "notes": "l"+                            },+                            "( > 1.1.1 ) || ( < 1.1.1 ) || ( < 1.2.1 )": {+                                "distroPKGs": [+                                    "c",+                                    "d"+                                ],+                                "notes": "sw"+                            },+                            "( > 2.2.1 ) || ( == 2.1.1 && > 1.1.2 )": {+                                "distroPKGs": [+                                    "vd",+                                    "",+                                    "ow"+                                ],+                                "notes": "xhcd"+                            },+                            "( >= 2.1.1 && < 1.2.2 && >= 1.2.1 && < 2.2.3 )": {+                                "distroPKGs": [+                                    "esm",+                                    "pmnn",+                                    "j",+                                    ""+                                ],+                                "notes": ""+                            },+                            "( >= 2.1.1 && > 2.1.1 && < 2.1.1 )": {+                                "distroPKGs": [+                                    "mhn"+                                ],+                                "notes": "cx"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "",+                                    "",+                                    "",+                                    ""+                                ],+                                "notes": "d"+                            }+                        },+                        "FreeBSD": {+                            "( < 1.1.1 ) || ( == 1.1.1 )": {+                                "distroPKGs": [+                                    "tfw"+                                ],+                                "notes": "pz"+                            },+                            "( < 1.2.1 && < 1.1.1 ) || ( > 1.2.1 ) || ( > 1.2.1 )": {+                                "distroPKGs": [+                                    "pcc",+                                    "pu",+                                    "xfr"+                                ],+                                "notes": ""+                            },+                            "( <= 3.2.1 )": {+                                "distroPKGs": [+                                    ""+                                ],+                                "notes": ""+                            },+                            "( == 2.2.2 && > 2.1.2 )": {+                                "distroPKGs": [+                                    "znta",+                                    "er"+                                ],+                                "notes": "au"+                            },+                            "( == 3.2.2 && == 1.2.1 )": {+                                "distroPKGs": [+                                    "zkyj",+                                    "htdv"+                                ],+                                "notes": "pa"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "w",+                                    "o",+                                    "uve"+                                ],+                                "notes": "bq"+                            }+                        },+                        "Windows": {+                            "( == 1.1.1 && >= 1.1.1 ) || ( > 1.1.1 )": {+                                "distroPKGs": [+                                    "f",+                                    "jufy",+                                    "eif",+                                    ""+                                ],+                                "notes": "w"+                            },+                            "( >= 2.1.2 && <= 1.2.2 && >= 1.1.1 && > 2.1.1 )": {+                                "distroPKGs": [+                                    "d"+                                ],+                                "notes": "cffa"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [],+                                "notes": ""+                            }+                        }+                    }+                },+                "?\u0014s": {+                    "2.5.6": {+                        "FreeBSD": {+                            "( <= 2.1.2 && == 2.2.2 && == 2.2.2 )": {+                                "distroPKGs": [],+                                "notes": "ucso"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [],+                                "notes": "x"+                            }+                        }+                    },+                    "5.4.1": {+                        "FreeBSD": {},+                        "Windows": {+                            "( < 3.2.1 && <= 1.1.1 && >= 2.1.1 && < 2.1.2 )": {+                                "distroPKGs": [+                                    "cpyk",+                                    "",+                                    "",+                                    "xlc"+                                ],+                                "notes": "xzmh"+                            },+                            "( <= 1.2.1 && > 2.1.1 )": {+                                "distroPKGs": [+                                    "pn",+                                    "",+                                    "a",+                                    "im"+                                ],+                                "notes": "tetf"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [],+                                "notes": "uoq"+                            }+                        }+                    },+                    "7.5.7": {+                        "Darwin": {+                            "( <= 1.1.1 ) || ( <= 1.1.1 && >= 2.2.1 )": {+                                "distroPKGs": [+                                    "y"+                                ],+                                "notes": ""+                            },+                            "( <= 1.1.1 ) || ( > 1.1.1 ) || ( >= 1.1.1 ) || ( > 2.2.2 )": {+                                "distroPKGs": [+                                    "vcse",+                                    "kfbx"+                                ],+                                "notes": "tinp"+                            },+                            "( <= 2.1.2 && == 2.1.3 ) || ( == 1.1.1 ) || ( < 1.1.1 ) || ( == 1.1.1 )": {+                                "distroPKGs": [],+                                "notes": "vmz"+                            },+                            "( <= 2.2.1 )": {+                                "distroPKGs": [+                                    "zws"+                                ],+                                "notes": "ykk"+                            },+                            "( == 1.1.1 && < 1.1.2 && > 1.1.1 ) || ( == 2.2.2 && < 1.2.1 )": {+                                "distroPKGs": [],+                                "notes": "cqpr"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "vgbb",+                                    "ncvm"+                                ],+                                "notes": ""+                            }+                        },+                        "FreeBSD": {+                            "( < 1.1.1 && >= 1.1.1 ) || ( >= 1.1.1 )": {+                                "distroPKGs": [+                                    "sqob"+                                ],+                                "notes": "iuel"+                            },+                            "( > 1.1.2 && <= 1.1.1 ) || ( < 1.1.1 )": {+                                "distroPKGs": [+                                    "o",+                                    "gzk"+                                ],+                                "notes": "h"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [],+                                "notes": "cgm"+                            }+                        },+                        "Linux_Debian": {+                            "( < 1.1.2 )": {+                                "distroPKGs": [],+                                "notes": "d"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "k",+                                    "vmw"+                                ],+                                "notes": "zri"+                            }+                        },+                        "Linux_Mint": {+                            "( > 2.1.1 ) || ( > 1.1.1 ) || ( == 2.1.1 ) || ( > 1.1.2 )": {+                                "distroPKGs": [+                                    "dgto",+                                    "adwn",+                                    ""+                                ],+                                "notes": "lc"+                            },+                            "( > 2.1.2 && <= 1.3.1 )": {+                                "distroPKGs": [+                                    "lyr",+                                    "rzs",+                                    "o",+                                    ""+                                ],+                                "notes": "u"+                            },+                            "( >= 2.1.2 && >= 1.1.1 )": {+                                "distroPKGs": [+                                    "olh",+                                    "ca",+                                    "onek",+                                    ""+                                ],+                                "notes": "mg"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "difw",+                                    "ykdo"+                                ],+                                "notes": "zd"+                            }+                        },+                        "OpenBSD": {},+                        "Windows": {+                            "( < 1.3.2 && <= 2.1.1 && >= 1.2.1 && < 2.1.2 )": {+                                "distroPKGs": [+                                    "zq",+                                    "qo"+                                ],+                                "notes": "do"+                            },+                            "( >= 2.2.1 ) || ( >= 1.1.1 )": {+                                "distroPKGs": [+                                    "rjzr",+                                    "wq",+                                    ""+                                ],+                                "notes": "prw"+                            }+                        }+                    },+                    "unknown_version": {+                        "FreeBSD": {+                            "( == 1.1.1 && > 1.1.1 && < 1.2.2 && <= 2.2.2 )": {+                                "distroPKGs": [+                                    ""+                                ],+                                "notes": ""+                            },+                            "( == 1.1.2 && >= 2.1.1 && < 2.1.1 && <= 1.1.2 )": {+                                "distroPKGs": [+                                    "xmh",+                                    "r",+                                    "vl",+                                    "xiea"+                                ],+                                "notes": ""+                            }+                        },+                        "Linux_AmazonLinux": {+                            "( <= 2.2.1 && > 1.1.2 && <= 2.2.2 && == 2.2.2 )": {+                                "distroPKGs": [+                                    ""+                                ],+                                "notes": "hhso"+                            }+                        },+                        "OpenBSD": {+                            "( < 2.1.1 && > 1.1.1 ) || ( > 1.1.1 && == 1.1.1 ) || ( > 1.1.1 ) || ( < 1.1.1 )": {+                                "distroPKGs": [],+                                "notes": "krb"+                            },+                            "( > 1.2.2 && > 1.3.2 && > 2.3.3 && == 4.2.1 )": {+                                "distroPKGs": [+                                    "mzm",+                                    "loc"+                                ],+                                "notes": "i"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "p",+                                    "",+                                    "cxh",+                                    "ljcb"+                                ],+                                "notes": ""+                            }+                        },+                        "Windows": {+                            "( < 1.1.1 ) || ( < 2.1.1 && >= 1.1.1 )": {+                                "distroPKGs": [+                                    "g",+                                    "ui",+                                    "onqc"+                                ],+                                "notes": ""+                            },+                            "( <= 1.1.1 && > 2.2.1 && == 2.2.1 )": {+                                "distroPKGs": [+                                    "",+                                    "j",+                                    "",+                                    "rqn"+                                ],+                                "notes": "b"+                            },+                            "( <= 1.1.2 && < 1.1.1 && < 1.1.2 && == 1.3.1 )": {+                                "distroPKGs": [+                                    "",+                                    "e",+                                    "assp",+                                    "tt"+                                ],+                                "notes": "omp"+                            },+                            "( <= 1.1.3 && >= 1.1.1 ) || ( >= 1.1.1 && <= 1.1.1 )": {+                                "distroPKGs": [+                                    "gvi",+                                    "",+                                    "ay"+                                ],+                                "notes": "lnvt"+                            },+                            "( == 1.2.1 && < 2.1.2 )": {+                                "distroPKGs": [+                                    "wami"+                                ],+                                "notes": ""+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "",+                                    "owpc"+                                ],+                                "notes": "yje"+                            }+                        }+                    }+                },+                "f\u0002": {+                    "3.6.2": {},+                    "5.5.3": {},+                    "6.8.7": {+                        "Darwin": {+                            "( < 2.2.1 && <= 2.2.2 )": {+                                "distroPKGs": [+                                    "de",+                                    "ox"+                                ],+                                "notes": ""+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "u",+                                    "vpps",+                                    "tret",+                                    "w"+                                ],+                                "notes": "ppt"+                            }+                        },+                        "FreeBSD": {+                            "( < 1.2.2 && <= 2.1.2 && <= 1.2.1 && < 1.2.1 )": {+                                "distroPKGs": [+                                    ""+                                ],+                                "notes": "fim"+                            },+                            "( <= 1.1.1 && >= 1.1.1 && > 1.2.1 ) || ( < 2.1.1 ) || ( == 1.1.1 ) || ( > 1.1.1 )": {+                                "distroPKGs": [],+                                "notes": "ej"+                            },+                            "( == 1.2.1 && <= 1.1.2 && < 1.2.1 ) || ( < 1.1.1 ) || ( == 1.1.1 ) || ( < 2.1.1 )": {+                                "distroPKGs": [+                                    "tu",+                                    "",+                                    "j",+                                    "tv"+                                ],+                                "notes": "drq"+                            },+                            "( >= 1.1.1 && >= 1.1.1 ) || ( < 2.1.1 && > 1.1.1 ) || ( <= 2.1.1 ) || ( < 2.1.1 )": {+                                "distroPKGs": [+                                    "fv"+                                ],+                                "notes": "c"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "g",+                                    "srvi"+                                ],+                                "notes": "elio"+                            }+                        }+                    },+                    "unknown_version": {+                        "FreeBSD": {},+                        "OpenBSD": {+                            "( <= 1.2.1 && <= 2.2.2 )": {+                                "distroPKGs": [+                                    "oedy",+                                    "kss"+                                ],+                                "notes": "ljv"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "",+                                    "",+                                    "am"+                                ],+                                "notes": "tc"+                            }+                        }+                    }+                },+                "xe&": {+                    "1.3.1": {+                        "FreeBSD": {+                            "( <= 1.1.1 ) || ( <= 1.2.1 ) || ( > 1.2.2 )": {+                                "distroPKGs": [+                                    "he",+                                    ""+                                ],+                                "notes": "jqi"+                            }+                        },+                        "OpenBSD": {+                            "( < 2.1.1 && >= 2.2.2 && < 1.2.2 )": {+                                "distroPKGs": [+                                    "xesg",+                                    "ka",+                                    "igs"+                                ],+                                "notes": "s"+                            },+                            "( <= 1.2.3 && <= 3.4.1 )": {+                                "distroPKGs": [+                                    "",+                                    "yfwo"+                                ],+                                "notes": "lk"+                            },+                            "( > 1.1.2 )": {+                                "distroPKGs": [+                                    "b"+                                ],+                                "notes": "o"+                            },+                            "( > 2.2.1 && > 2.2.2 && >= 2.2.1 && <= 2.2.1 )": {+                                "distroPKGs": [+                                    "gvzo"+                                ],+                                "notes": "afvr"+                            }+                        },+                        "Windows": {+                            "( == 2.1.1 ) || ( == 1.1.1 ) || ( >= 1.1.1 ) || ( <= 2.1.1 )": {+                                "distroPKGs": [+                                    "lyn",+                                    "ac",+                                    "",+                                    ""+                                ],+                                "notes": "uqj"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [+                                    "uzi"+                                ],+                                "notes": ""+                            }+                        }+                    },+                    "1.5.4": {+                        "Linux_Void": {}+                    },+                    "5.8.6": {+                        "Windows": {+                            "( < 1.1.1 ) || ( >= 1.1.1 && >= 2.1.1 )": {+                                "distroPKGs": [+                                    "cl"+                                ],+                                "notes": ""+                            },+                            "( == 2.2.1 && <= 2.1.2 && <= 2.1.2 )": {+                                "distroPKGs": [+                                    "lhvn",+                                    "aduq",+                                    "rdoh"+                                ],+                                "notes": "z"+                            },+                            "( >= 1.1.1 ) || ( == 1.1.1 ) || ( > 2.1.1 )": {+                                "distroPKGs": [+                                    "hma",+                                    "i",+                                    ""+                                ],+                                "notes": ""+                            },+                            "( >= 2.1.1 && <= 1.1.1 && < 1.1.1 ) || ( > 1.1.1 && > 1.1.1 ) || ( >= 1.1.2 ) || ( > 2.1.1 )": {+                                "distroPKGs": [+                                    "mk",+                                    "",+                                    "lg",+                                    "zp"+                                ],+                                "notes": "k"+                            }+                        }+                    },+                    "unknown_version": {+                        "Darwin": {+                            "( >= 1.1.1 )": {+                                "distroPKGs": [+                                    "e"+                                ],+                                "notes": "uk"+                            }+                        },+                        "FreeBSD": {+                            "( <= 2.3.2 && > 1.2.1 )": {+                                "distroPKGs": [],+                                "notes": "gz"+                            },+                            "( == 1.2.2 )": {+                                "distroPKGs": [+                                    "jb",+                                    "wzuq",+                                    "jjis"+                                ],+                                "notes": ""+                            },+                            "( > 3.2.2 )": {+                                "distroPKGs": [+                                    "ncdi",+                                    "m"+                                ],+                                "notes": "c"+                            },+                            "( >= 1.1.1 ) || ( > 1.1.1 )": {+                                "distroPKGs": [+                                    "yzmz",+                                    "",+                                    "yn",+                                    "u"+                                ],+                                "notes": "imjq"+                            },+                            "( >= 2.1.2 )": {+                                "distroPKGs": [+                                    "rz",+                                    ""+                                ],+                                "notes": "ahhy"+                            },+                            "( >= 3.2.2 )": {+                                "distroPKGs": [+                                    "xwyt"+                                ],+                                "notes": ""+                            }+                        },+                        "Linux_Alpine": {+                            "( <= 1.1.1 && >= 2.1.1 ) || ( == 1.2.1 )": {+                                "distroPKGs": [],+                                "notes": "wbh"+                            },+                            "( <= 1.2.1 && < 1.1.1 && >= 1.1.1 ) || ( < 1.1.1 )": {+                                "distroPKGs": [+                                    ""+                                ],+                                "notes": "i"+                            },+                            "( <= 2.1.1 && >= 1.2.2 && >= 1.2.1 ) || ( < 2.1.1 )": {+                                "distroPKGs": [],+                                "notes": "zyyh"+                            },+                            "( == 2.1.1 ) || ( > 1.1.1 ) || ( <= 1.1.2 ) || ( < 2.1.2 )": {+                                "distroPKGs": [],+                                "notes": "ael"+                            },+                            "( == 2.1.2 && < 1.2.2 && < 1.2.1 ) || ( == 1.1.1 )": {+                                "distroPKGs": [+                                    "i"+                                ],+                                "notes": "ob"+                            },+                            "( > 2.2.1 && < 4.2.2 )": {+                                "distroPKGs": [+                                    "db"+                                ],+                                "notes": "embx"+                            },+                            "unknown_versioning": {+                                "distroPKGs": [],+                                "notes": "ol"+                            }+                        },+                        "Linux_Ubuntu": {+                            "( <= 1.2.2 && < 2.1.1 && > 2.2.3 && <= 2.3.2 )": {+                                "distroPKGs": [],+                                "notes": "xlyq"+                            },+                            "( > 2.2.1 && >= 1.1.1 )": {+                                "distroPKGs": [+                                    "",+                                    "pu",+                                    "m",+                                    "uwo"+                                ],+                                "notes": ""+                            }+                        },+                        "OpenBSD": {+                            "( < 1.1.1 && <= 1.2.2 && >= 1.1.1 ) || ( < 1.1.1 )": {+                                "distroPKGs": [+                                    "nki"+                                ],+                                "notes": "mozu"+                            },+                            "( < 1.1.3 && <= 2.1.1 && <= 1.2.1 ) || ( >= 1.1.1 && > 2.1.1 )": {+                                "distroPKGs": [+                                    "by",+                                    "hfgv"+                                ],+                                "notes": "e"+                            },+                            "( == 1.1.2 ) || ( > 1.1.2 && >= 1.2.1 )": {+                                "distroPKGs": [+                                    "k",+                                    "e"+                                ],+                                "notes": "un"+                            },+                            "( > 2.1.1 ) || ( >= 1.1.1 )": {+                                "distroPKGs": [],+                                "notes": ""+                            }+                        },+                        "Windows": {+                            "( == 2.1.3 )": {+                                "distroPKGs": [+                                    "of",+                                    ""+                                ],+                                "notes": "g"+                            }+                        }+                    }+                }+            }+        }+    ],+    "seed": 1832749699 }
test/optparse-test/ChangeLogTest.hs view
@@ -23,23 +23,21 @@ checkList =   [ ("changelog", ChangeLogOptions False Nothing Nothing)   , ("changelog -o", ChangeLogOptions True Nothing Nothing)-  , ("changelog -t ghc", ChangeLogOptions False (Just GHC) Nothing)-  , ("changelog -t cabal", ChangeLogOptions False (Just Cabal) Nothing)-  , ("changelog -t hls", ChangeLogOptions False (Just HLS) Nothing)-  , ("changelog -t stack", ChangeLogOptions False (Just Stack) Nothing)-  , ("changelog -t ghcup", ChangeLogOptions False (Just GHCup) Nothing)+  , ("changelog -t ghc", ChangeLogOptions False (Just ghc) Nothing)+  , ("changelog -t cabal", ChangeLogOptions False (Just cabal) Nothing)+  , ("changelog -t hls", ChangeLogOptions False (Just hls) Nothing)+  , ("changelog -t stack", ChangeLogOptions False (Just stack) Nothing)+  , ("changelog -t ghcup", ChangeLogOptions False (Just ghcup) Nothing)   , ("changelog 9.2", ChangeLogOptions False Nothing       (Just $ GHCVersion-        $ GHCTargetVersion-          Nothing+        $ toTargetVersionReq''           $(versionQ "9.2"))     )   , ("changelog recommended", ChangeLogOptions False Nothing (Just $ ToolTag Recommended))-  , ("changelog -t cabal recommended", ChangeLogOptions False (Just Cabal) (Just $ ToolTag Recommended))-  , ("changelog -t cabal 3.10.1.0", ChangeLogOptions False (Just Cabal)+  , ("changelog -t cabal recommended", ChangeLogOptions False (Just cabal) (Just $ ToolTag Recommended))+  , ("changelog -t cabal 3.10.1.0", ChangeLogOptions False (Just cabal)       (Just $ GHCVersion-        $ GHCTargetVersion-          Nothing+        $ toTargetVersionReq''           $(versionQ "3.10.1.0"))     )   , ("changelog 2023-07-22", ChangeLogOptions False Nothing (Just (ToolDay (read "2023-07-22"))))
test/optparse-test/CompileTest.hs view
@@ -13,8 +13,8 @@ import URI.ByteString.QQ import qualified GHCup.OptParse.Compile as GHC (GHCCompileOptions(..)) import qualified GHCup.OptParse.Compile as HLS (HLSCompileOptions(..))-import GHCup.GHC as GHC-import GHCup.HLS as HLS+import GHCup.Command.Compile.GHC as GHC+import GHCup.Command.Compile.HLS as HLS   compileTests :: TestTree@@ -40,7 +40,7 @@     Nothing     Nothing     Nothing-    "install"+    Nothing  mkDefaultHLSCompileOptions :: HLSVer -> [ToolVersion] -> HLSCompileOptions mkDefaultHLSCompileOptions target ghcs =@@ -204,7 +204,7 @@         [ghc928]      ghc928 :: ToolVersion-    ghc928 = GHCVersion $ GHCTargetVersion Nothing $(versionQ "9.2.8")+    ghc928 = GHCVersion $ toTargetVersionReq'' $(versionQ "9.2.8")  compileParseWith :: [String] -> IO CompileCommand compileParseWith args = do
test/optparse-test/ConfigTest.hs view
@@ -48,6 +48,24 @@     , AddReleaseChannel False (NewChannelAlias VanillaChannel)     )   , ("config set cache true", SetConfig "cache" (Just "true"))+  , ("config reset all", ResetConfig ResetAll)+  , ("config reset keys cache downloader", ResetConfig (ResetKeys ["cache", "downloader"]))+  , ("config reset keys cache", ResetConfig (ResetKeys ["cache"]))+  , ("config reset keys meta-cache", ResetConfig (ResetKeys ["meta-cache"]))+  , ("config reset keys meta-mode", ResetConfig (ResetKeys ["meta-mode"]))+  , ("config reset keys no-verify", ResetConfig (ResetKeys ["no-verify"]))+  , ("config reset keys verbose", ResetConfig (ResetKeys ["verbose"]))+  , ("config reset keys keep-dirs", ResetConfig (ResetKeys ["keep-dirs"]))+  , ("config reset keys downloader", ResetConfig (ResetKeys ["downloader"]))+  , ("config reset keys key-bindings", ResetConfig (ResetKeys ["key-bindings"]))+  , ("config reset keys url-source", ResetConfig (ResetKeys ["url-source"]))+  , ("config reset keys no-network", ResetConfig (ResetKeys ["no-network"]))+  , ("config reset keys gpg-setting", ResetConfig (ResetKeys ["gpg-setting"]))+  , ("config reset keys platform-override", ResetConfig (ResetKeys ["platform-override"]))+  , ("config reset keys mirrors", ResetConfig (ResetKeys ["mirrors"]))+  , ("config reset keys def-ghc-conf-options", ResetConfig (ResetKeys ["def-ghc-conf-options"]))+  , ("config reset keys pager", ResetConfig (ResetKeys ["pager"]))+  , ("config reset keys guess-version", ResetConfig (ResetKeys ["guess-version"]))   ]  configParseWith :: [String] -> IO ConfigCommand
test/optparse-test/InstallTest.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes       #-} {-# LANGUAGE TemplateHaskell   #-}+{-# LANGUAGE DuplicateRecordFields #-}  module InstallTest where @@ -11,8 +12,6 @@ import GHCup.Types import Data.Versions import Data.List.NonEmpty (NonEmpty ((:|)))-import GHCup.OptParse.Install as Install-import URI.ByteString.QQ  -- Some interests: --   install ghc *won't* select `set as activate version` as default@@ -24,180 +23,101 @@ installTests = testGroup "install"   $ map       (buildTestTree installParseWith)-      [ ("old-style", oldStyleCheckList)-      , ("ghc", installGhcCheckList)+      [ ("ghc", installGhcCheckList)       , ("cabal", installCabalCheckList)       , ("hls", installHlsCheckList)       , ("stack", installStackCheckList)       ]  defaultOptions :: InstallOptions-defaultOptions = InstallOptions Nothing Nothing False Nothing False "install" []+defaultOptions = InstallOptions Nothing Nothing False Nothing False Nothing []  -- | Don't set as active version mkInstallOptions :: ToolVersion -> InstallOptions-mkInstallOptions ver = InstallOptions (Just ver) Nothing False Nothing False "install" []+mkInstallOptions ver = InstallOptions (Just ver) Nothing False Nothing False Nothing []  -- | Set as active version mkInstallOptions' :: ToolVersion -> InstallOptions-mkInstallOptions' ver = InstallOptions (Just ver) Nothing True Nothing False "install" []--oldStyleCheckList :: [(String, Either InstallCommand InstallOptions)]-oldStyleCheckList =-      ("install", Right defaultOptions)-    : ("install --set", Right defaultOptions{instSet = True})-    : ("install --force", Right defaultOptions{forceInstall = True})-#ifdef IS_WINDOWS-    : ("install -i C:\\\\", Right defaultOptions{Install.isolateDir = Just "C:\\"})-#else-    : ("install -i /", Right defaultOptions{Install.isolateDir = Just "/"})-#endif-    : ("install -u https://gitlab.haskell.org/ghc/ghc/-/jobs/artifacts/master/raw/ghc-x86_64-linux-fedora33-release.tar.xz head"-    , Right defaultOptions-        { instBindist = Just [uri|https://gitlab.haskell.org/ghc/ghc/-/jobs/artifacts/master/raw/ghc-x86_64-linux-fedora33-release.tar.xz|]-        , instVer = Just $ GHCVersion $ GHCTargetVersion Nothing  $(versionQ "head")-        }-    )-    : mapSecond-        (Right . mkInstallOptions)-        [ ("install ghc-9.2", GHCVersion-              $ GHCTargetVersion-                (Just "ghc")-                $(versionQ "9.2")-          )-          -- invalid-        , ("install next", GHCVersion-              $ GHCTargetVersion-                Nothing-                $(versionQ "next")-          )-        , ("install latest", ToolTag Latest)-        , ("install nightly", GHCVersion-              $ GHCTargetVersion-                Nothing-                $(versionQ "nightly")-          )-        , ("install recommended", ToolTag Recommended)-        , ("install prerelease", GHCVersion-              $ GHCTargetVersion-                Nothing-                $(versionQ "prerelease")-          )-        , ("install latest-prerelease", ToolTag LatestPrerelease)-        , ("install latest-nightly", ToolTag LatestNightly)-        , ("install ghc-javascript-unknown-ghcjs-9.6", GHCVersion-              $ GHCTargetVersion-                (Just "ghc-javascript-unknown-ghcjs")-                $(versionQ "9.6")-          )-        , ("install base-4.18", ToolTag (Base (PVP {_pComponents = 4 :| [18]})))-        , ("install cabal-3.10", GHCVersion-              $ GHCTargetVersion-                (Just "cabal")-                $(versionQ "3.10")-          )-        , ("install hls-2.0.0.0", GHCVersion-              $ GHCTargetVersion-                (Just "hls")-                $(versionQ "2.0.0.0")-          )-        , ("install stack-2.9.3", GHCVersion-              $ GHCTargetVersion-                (Just "stack")-                $(versionQ "2.9.3")-          )-        ]+mkInstallOptions' ver = InstallOptions (Just ver) Nothing True Nothing False Nothing [] -installGhcCheckList :: [(String, Either InstallCommand InstallOptions)]+installGhcCheckList :: [(String, InstallCommand)] installGhcCheckList =-  ("install ghc", Left $ InstallGHC defaultOptions)-  : mapSecond (Left . InstallGHC . mkInstallOptions)+  ("install ghc", InstallGHC defaultOptions)+  : mapSecond (InstallGHC . mkInstallOptions)     [ ("install ghc 9.2", GHCVersion-          $ GHCTargetVersion-            Nothing+          $ toTargetVersionReq''             $(versionQ "9.2")       )     , ("install ghc next", GHCVersion-          $ GHCTargetVersion-            Nothing+          $ toTargetVersionReq''             $(versionQ "next")       )     , ("install ghc latest", ToolTag Latest)     , ("install ghc nightly", GHCVersion-          $ GHCTargetVersion-            Nothing+          $ toTargetVersionReq''             $(versionQ "nightly")       )     , ("install ghc recommended", ToolTag Recommended)     , ("install ghc prerelease", GHCVersion-          $ GHCTargetVersion-            Nothing+          $ toTargetVersionReq''             $(versionQ "prerelease")       )     , ("install ghc latest-prerelease", ToolTag LatestPrerelease)     , ("install ghc latest-nightly", ToolTag LatestNightly)     , ("install ghc javascript-unknown-ghcjs-9.6", GHCVersion-          $ GHCTargetVersion+          $ (`TargetVersionReq` Nothing) $ TargetVersion             (Just "javascript-unknown-ghcjs")             $(versionQ "9.6")       )     , ("install ghc base-4.18", ToolTag (Base (PVP {_pComponents = 4 :| [18]})))-    , ("install ghc ghc-9.2", GHCVersion-          $ GHCTargetVersion-            (Just "ghc")-            $(versionQ "9.2")-      )     ] -installCabalCheckList :: [(String, Either InstallCommand InstallOptions)]+installCabalCheckList :: [(String, InstallCommand)] installCabalCheckList =-  ("install cabal", Left $ InstallCabal defaultOptions{instSet = True})-  : mapSecond (Left . InstallCabal . mkInstallOptions')-    [ ("install cabal 3.10", ToolVersion $(versionQ "3.10"))-    , ("install cabal next", ToolVersion $(versionQ "next"))+  ("install cabal", InstallCabal (defaultOptions{ instSet = True } :: InstallOptions))+  : mapSecond (InstallCabal . mkInstallOptions')+    [ ("install cabal 3.10", ToolVersion $ (`VersionReq` Nothing) $(versionQ "3.10"))+    , ("install cabal next", ToolVersion $ (`VersionReq` Nothing) $(versionQ "next"))     , ("install cabal latest", ToolTag Latest)-    , ("install cabal nightly", ToolVersion $(versionQ "nightly"))+    , ("install cabal nightly", ToolVersion $ (`VersionReq` Nothing) $(versionQ "nightly"))     , ("install cabal recommended", ToolTag Recommended)-    , ("install cabal prerelease", ToolVersion $(versionQ "prerelease"))+    , ("install cabal prerelease", ToolVersion $ (`VersionReq` Nothing) $(versionQ "prerelease"))     , ("install cabal latest-prerelease", ToolTag LatestPrerelease)     , ("install cabal latest-nightly", ToolTag LatestNightly)     , ("install cabal base-4.18", ToolTag (Base (PVP {_pComponents = 4 :| [18]})))-    , ("install cabal cabal-3.10", ToolVersion $(versionQ "cabal-3.10"))     ] -installHlsCheckList :: [(String, Either InstallCommand InstallOptions)]+installHlsCheckList :: [(String, InstallCommand)] installHlsCheckList =-  ("install hls", Left $ InstallHLS defaultOptions{instSet = True})-  : mapSecond (Left . InstallHLS . mkInstallOptions')-    [ ("install hls 3.10", ToolVersion $(versionQ "3.10"))-    , ("install hls next", ToolVersion $(versionQ "next"))+  ("install hls", InstallHLS defaultOptions{instSet = True})+  : mapSecond (InstallHLS . mkInstallOptions')+    [ ("install hls 3.10", ToolVersion $ (`VersionReq` Nothing) $(versionQ "3.10"))+    , ("install hls next", ToolVersion $ (`VersionReq` Nothing) $(versionQ "next"))     , ("install hls latest", ToolTag Latest)-    , ("install hls nightly", ToolVersion $(versionQ "nightly"))+    , ("install hls nightly", ToolVersion $ (`VersionReq` Nothing) $(versionQ "nightly"))     , ("install hls recommended", ToolTag Recommended)-    , ("install hls prerelease", ToolVersion $(versionQ "prerelease"))+    , ("install hls prerelease", ToolVersion $ (`VersionReq` Nothing) $(versionQ "prerelease"))     , ("install hls latest-prerelease", ToolTag LatestPrerelease)     , ("install hls latest-nightly", ToolTag LatestNightly)     , ("install hls base-4.18", ToolTag (Base (PVP {_pComponents = 4 :| [18]})))-    , ("install hls hls-2.0", ToolVersion $(versionQ "hls-2.0"))     ] -installStackCheckList :: [(String, Either InstallCommand InstallOptions)]+installStackCheckList :: [(String, InstallCommand)] installStackCheckList =-  ("install stack", Left $ InstallStack defaultOptions{instSet = True})-  : mapSecond (Left . InstallStack . mkInstallOptions')-    [ ("install stack 3.10", ToolVersion $(versionQ "3.10"))-    , ("install stack next", ToolVersion $(versionQ "next"))+  ("install stack", InstallStack defaultOptions{instSet = True})+  : mapSecond (InstallStack . mkInstallOptions')+    [ ("install stack 3.10", ToolVersion $ (`VersionReq` Nothing) $(versionQ "3.10"))+    , ("install stack next", ToolVersion $ (`VersionReq` Nothing) $(versionQ "next"))     , ("install stack latest", ToolTag Latest)-    , ("install stack nightly", ToolVersion $(versionQ "nightly"))+    , ("install stack nightly", ToolVersion $ (`VersionReq` Nothing) $(versionQ "nightly"))     , ("install stack recommended", ToolTag Recommended)-    , ("install stack prerelease", ToolVersion $(versionQ "prerelease"))+    , ("install stack prerelease", ToolVersion $ (`VersionReq` Nothing) $(versionQ "prerelease"))     , ("install stack latest-prerelease", ToolTag LatestPrerelease)     , ("install stack latest-nightly", ToolTag LatestNightly)     , ("install stack base-4.18", ToolTag (Base (PVP {_pComponents = 4 :| [18]})))-    , ("install stack stack-2.9", ToolVersion $(versionQ "stack-2.9"))     ] -installParseWith :: [String] -> IO (Either InstallCommand InstallOptions)+installParseWith :: [String] -> IO InstallCommand installParseWith args = do   Install a <- parseWith args   pure a
test/optparse-test/ListTest.hs view
@@ -3,7 +3,7 @@ import Test.Tasty import GHCup.OptParse import Utils-import GHCup.List+import GHCup.Command.List import GHCup.Types  @@ -11,33 +11,34 @@ listTests = buildTestTree listParseWith ("list", listCheckList)  defaultOptions :: ListOptions-defaultOptions = ListOptions Nothing Nothing Nothing Nothing False False False+defaultOptions = ListOptions Nothing [] Nothing Nothing False False False ShowUpdates  listCheckList :: [(String, ListOptions)] listCheckList =-  [ ("list", defaultOptions)-  , ("list -t ghc", defaultOptions{loTool = Just GHC})-  , ("list -t cabal", defaultOptions{loTool = Just Cabal})-  , ("list -t hls", defaultOptions{loTool = Just HLS})-  , ("list -t stack", defaultOptions{loTool = Just Stack})-  , ("list -c installed", defaultOptions{lCriteria = Just $ ListInstalled True})-  , ("list -c +installed", defaultOptions{lCriteria = Just $ ListInstalled True})-  , ("list -c -installed", defaultOptions{lCriteria = Just $ ListInstalled False})-  , ("list -c set", defaultOptions{lCriteria = Just $ ListSet True})-  , ("list -c +set", defaultOptions{lCriteria = Just $ ListSet True})-  , ("list -c -set", defaultOptions{lCriteria = Just $ ListSet False})-  , ("list -c available", defaultOptions{lCriteria = Just $ ListAvailable True})-  , ("list -c +available", defaultOptions{lCriteria = Just $ ListAvailable True})-  , ("list -c -available", defaultOptions{lCriteria = Just $ ListAvailable False})-  , ("list -s 2023-07-22", defaultOptions{lFrom = Just $ read "2023-07-22"})-  , ("list -u 2023-07-22", defaultOptions{lTo = Just $ read "2023-07-22"})-  , ("list --since 2023-07-22 --until 2023-07-22", defaultOptions{lFrom = Just $ read "2023-07-22", lTo = Just $ read "2023-07-22"})-  , ("list -o", defaultOptions{lHideOld = True})-  , ("list --hide-old", defaultOptions{lHideOld = True})-  , ("list -n", defaultOptions{lShowNightly = True})+  [ ("list",                defaultOptions)+  , ("list -t ghc",         defaultOptions{loTool = Just [ghc]})+  , ("list -t cabal",       defaultOptions{loTool = Just [cabal]})+  , ("list -t hls",         defaultOptions{loTool = Just [hls]})+  , ("list -t stack",       defaultOptions{loTool = Just [stack]})+  , ("list -c installed",   defaultOptions{lCriteria = [ListInstalled True]})+  , ("list -c +installed",  defaultOptions{lCriteria = [ListInstalled True]})+  , ("list -c -installed",  defaultOptions{lCriteria = [ListInstalled False]})+  , ("list -c set",         defaultOptions{lCriteria = [ListSet True]})+  , ("list -c +set",        defaultOptions{lCriteria = [ListSet True]})+  , ("list -c -set",        defaultOptions{lCriteria = [ListSet False]})+  , ("list -c available",   defaultOptions{lCriteria = [ListAvailable True]})+  , ("list -c +available",  defaultOptions{lCriteria = [ListAvailable True]})+  , ("list -c -available",  defaultOptions{lCriteria = [ListAvailable False]})+  , ("list -s 2023-07-22",  defaultOptions{lFrom = Just $ read "2023-07-22"})+  , ("list -u 2023-07-22",  defaultOptions{lTo = Just $ read "2023-07-22"})+  , ("list --since 2023-07-22 --until 2023-07-22",+                            defaultOptions{lFrom = Just $ read "2023-07-22", lTo = Just $ read "2023-07-22"})+  , ("list -o",             defaultOptions{lHideOld = True})+  , ("list --hide-old",     defaultOptions{lHideOld = True})+  , ("list -n",             defaultOptions{lShowNightly = True})   , ("list --show-nightly", defaultOptions{lShowNightly = True})-  , ("list -r", defaultOptions{lRawFormat = True})-  , ("list --raw-format", defaultOptions{lRawFormat = True})+  , ("list -r",             defaultOptions{lRawFormat = True})+  , ("list --raw-format",   defaultOptions{lRawFormat = True})   ]  listParseWith :: [String] -> IO ListOptions
test/optparse-test/RmTest.hs view
@@ -14,49 +14,37 @@ rmTests =   testGroup "rm"     $ map (buildTestTree rmParseWith)-        [ ("old-style", oldStyleCheckList)-        , ("ghc", rmGhcCheckList)+        [ ("ghc", rmGhcCheckList)         , ("cabal", rmCabalCheckList)         , ("hls", rmHlsCheckList)         , ("stack", rmStackCheckList)         ] -oldStyleCheckList :: [(String, Either RmCommand RmOptions)]-oldStyleCheckList = mapSecond (Right . RmOptions)-  [ -- failed with ("rm", xxx)-    ("rm 9.2.8", mkTVer $(versionQ "9.2.8"))-  , ("rm ghc-9.2.8",  GHCTargetVersion (Just "ghc") $(versionQ "9.2.8"))-  ]--rmGhcCheckList :: [(String, Either RmCommand RmOptions)]-rmGhcCheckList = mapSecond (Left . RmGHC . RmOptions)+rmGhcCheckList :: [(String, RmCommand)]+rmGhcCheckList = mapSecond (RmGHC . RmOptions)   [ -- failed with ("rm ghc", xxx)     ("rm ghc 9.2.8", mkTVer $(versionQ "9.2.8"))-  , ("rm ghc ghc-9.2.8",  GHCTargetVersion (Just "ghc") $(versionQ "9.2.8"))   ] -rmCabalCheckList :: [(String, Either RmCommand RmOptions)]-rmCabalCheckList = mapSecond (Left . RmCabal)+rmCabalCheckList :: [(String, RmCommand)]+rmCabalCheckList = mapSecond RmCabal   [ -- failed with ("rm cabal", xxx)     ("rm cabal 3.10", $(versionQ "3.10"))-  , ("rm cabal cabal-3.10", $(versionQ "cabal-3.10"))   ] -rmHlsCheckList :: [(String, Either RmCommand RmOptions)]-rmHlsCheckList = mapSecond (Left . RmHLS)+rmHlsCheckList :: [(String, RmCommand)]+rmHlsCheckList = mapSecond RmHLS   [ -- failed with ("rm hls", xxx)     ("rm hls 2.0", $(versionQ "2.0"))-  , ("rm hls hls-2.0", $(versionQ "hls-2.0"))   ] -rmStackCheckList :: [(String, Either RmCommand RmOptions)]-rmStackCheckList = mapSecond (Left . RmStack)+rmStackCheckList :: [(String, RmCommand)]+rmStackCheckList = mapSecond RmStack   [ -- failed with ("rm stack", xxx)     ("rm stack 2.9.1", $(versionQ "2.9.1"))-  , ("rm stack stack-2.9.1", $(versionQ "stack-2.9.1"))   ] -rmParseWith :: [String] -> IO (Either RmCommand RmOptions)+rmParseWith :: [String] -> IO RmCommand rmParseWith args = do   Rm a <- parseWith args   pure a
test/optparse-test/RunTest.hs view
@@ -24,6 +24,7 @@     Nothing     Nothing     Nothing+    []     Nothing     False     []@@ -37,11 +38,11 @@   , ("run --install", defaultOptions{runInstTool' = True})   , ("run -m", defaultOptions{runMinGWPath = True})   , ("run --mingw-path", defaultOptions{runMinGWPath = True})-  , ("run --ghc 9.2.8", defaultOptions{runGHCVer = Just $ GHCVersion $ mkTVer $(versionQ "9.2.8")})+  , ("run --ghc 9.2.8", defaultOptions{runGHCVer = Just $ GHCVersion $ (`TargetVersionReq` Nothing) $ mkTVer $(versionQ "9.2.8")})   , ("run --ghc latest", defaultOptions{runGHCVer = Just $ ToolTag Latest})-  , ("run --cabal 3.10", defaultOptions{runCabalVer = Just $ ToolVersion $(versionQ "3.10")})-  , ("run --hls 2.0", defaultOptions{runHLSVer = Just $ ToolVersion $(versionQ "2.0")})-  , ("run --stack 2.9", defaultOptions{runStackVer = Just $ ToolVersion $(versionQ "2.9") })+  , ("run --cabal 3.10", defaultOptions{runCabalVer = Just $ ToolVersion $ (`VersionReq` Nothing) $(versionQ "3.10")})+  , ("run --hls 2.0", defaultOptions{runHLSVer = Just $ ToolVersion $ (`VersionReq` Nothing) $(versionQ "2.0")})+  , ("run --stack 2.9", defaultOptions{runStackVer = Just $ ToolVersion $ (`VersionReq` Nothing) $(versionQ "2.9") }) #ifdef IS_WINDOWS   , ("run -b C:\\\\tmp\\dir", defaultOptions{runBinDir = Just "C:\\tmp\\dir"})   , ("run --bindir C:\\\\tmp\\dir", defaultOptions{runBinDir = Just "C:\\tmp\\dir"})@@ -54,9 +55,9 @@   , ("run --ghc latest --cabal 3.10 --stack 2.9 --hls 2.0 --install",         defaultOptions           { runGHCVer = Just $ ToolTag Latest-          , runCabalVer = Just $ ToolVersion $(versionQ "3.10")-          , runHLSVer = Just $ ToolVersion $(versionQ "2.0")-          , runStackVer = Just $ ToolVersion $(versionQ "2.9")+          , runCabalVer = Just $ ToolVersion $ (`VersionReq` Nothing) $(versionQ "3.10")+          , runHLSVer = Just $ ToolVersion   $ (`VersionReq` Nothing) $(versionQ "2.0")+          , runStackVer = Just $ ToolVersion $ (`VersionReq` Nothing) $(versionQ "2.9")           , runInstTool' = True           }     )
test/optparse-test/SetTest.hs view
@@ -4,7 +4,7 @@ module SetTest where  import GHCup.OptParse-import GHCup.Utils.Parsers (SetToolVersion(..))+import GHCup.Input.Parsers (SetToolVersion(..)) import Test.Tasty import GHCup.Types import Data.Versions@@ -16,142 +16,90 @@   testGroup "set"     $ map         (buildTestTree setParseWith)-        [ ("old-style", oldStyleCheckList)-        , ("ghc", setGhcCheckList)+        [ ("ghc", setGhcCheckList)         , ("cabal", setCabalCheckList)         , ("hls", setHlsCheckList)         , ("stack", setStackCheckList)         ] -oldStyleCheckList :: [(String, Either SetCommand SetOptions)]-oldStyleCheckList = mapSecond (Right . SetOptions)-  [ ("set", SetRecommended)-  , ("set ghc-9.2", SetGHCVersion-          $ GHCTargetVersion-            (Just "ghc")-            $(versionQ "9.2")-    )-  , ("set next", SetNext)-  , ("set latest", SetToolTag Latest)-  , ("set nightly", SetGHCVersion-          $ GHCTargetVersion-            Nothing-            $(versionQ "nightly")-    )-    -- different from `set`-  , ("set recommended", SetToolTag Recommended)-  , ("set prerelease", SetGHCVersion-          $ GHCTargetVersion-            Nothing-            $(versionQ "prerelease")-    )-  , ("set latest-prerelease", SetToolTag LatestPrerelease)-  , ("set latest-nightly", SetToolTag LatestNightly)-  , ("set ghc-javascript-unknown-ghcjs-9.6", SetGHCVersion-          $ GHCTargetVersion-            (Just "ghc-javascript-unknown-ghcjs")-            $(versionQ "9.6")-    )-  , ("set base-4.18", SetToolTag (Base (PVP {_pComponents = 4 :| [18]})))-  , ("set cabal-3.10", SetGHCVersion-          $ GHCTargetVersion-            (Just "cabal")-            $(versionQ "3.10")-    )-  , ("set hls-2.0.0.0", SetGHCVersion-        $ GHCTargetVersion-            (Just "hls")-            $(versionQ "2.0.0.0")-    )-  , ("set stack-2.9.3", SetGHCVersion-        $ GHCTargetVersion-            (Just "stack")-            $(versionQ "2.9.3")-    )-  ]--setGhcCheckList :: [(String, Either SetCommand SetOptions)]-setGhcCheckList = mapSecond (Left . SetGHC . SetOptions)+setGhcCheckList :: [(String, SetCommand)]+setGhcCheckList = mapSecond (SetGHC . SetOptions)   [ ("set ghc", SetRecommended)   , ("set ghc 9.2", SetGHCVersion-        $ GHCTargetVersion+        $ (`TargetVersionReq` Nothing) $ TargetVersion           Nothing           $(versionQ "9.2")     )   , ("set ghc next", SetNext)   , ("set ghc latest", SetToolTag Latest)   , ("set ghc nightly", SetGHCVersion-        $ GHCTargetVersion+        $ (`TargetVersionReq` Nothing) $ TargetVersion           Nothing           $(versionQ "nightly")     )   , ("set ghc recommended", SetToolTag Recommended)   , ("set ghc prerelease", SetGHCVersion-        $ GHCTargetVersion+        $ (`TargetVersionReq` Nothing) $ TargetVersion           Nothing           $(versionQ "prerelease")     )   , ("set ghc latest-prerelease", SetToolTag LatestPrerelease)   , ("set ghc latest-nightly", SetToolTag LatestNightly)   , ("set ghc javascript-unknown-ghcjs-9.6", SetGHCVersion-        $ GHCTargetVersion+        $ (`TargetVersionReq` Nothing) $ TargetVersion           (Just "javascript-unknown-ghcjs")           $(versionQ "9.6")     )   , ("set ghc base-4.18", SetToolTag (Base (PVP {_pComponents = 4 :| [18]})))-  , ("set ghc ghc-9.2", SetGHCVersion-        $ GHCTargetVersion-          (Just "ghc")-          $(versionQ "9.2")-    )   ] -setCabalCheckList :: [(String, Either SetCommand SetOptions)]-setCabalCheckList = mapSecond (Left . SetCabal . SetOptions)+setCabalCheckList :: [(String, SetCommand)]+setCabalCheckList = mapSecond (SetCabal . SetOptions)   [ ("set cabal", SetRecommended)-  , ("set cabal 3.10", SetToolVersion $(versionQ "3.10"))+  , ("set cabal 3.10", SetToolVersion $ (`VersionReq` Nothing) $(versionQ "3.10"))   , ("set cabal next", SetNext)   , ("set cabal latest", SetToolTag Latest)-  , ("set cabal nightly", SetToolVersion $(versionQ "nightly"))+  , ("set cabal nightly", SetToolVersion $ (`VersionReq` Nothing) $(versionQ "nightly"))   , ("set cabal recommended", SetToolTag Recommended)-  , ("set cabal prerelease", SetToolVersion $(versionQ "prerelease"))+  , ("set cabal prerelease", SetToolVersion $ (`VersionReq` Nothing) $(versionQ "prerelease"))   , ("set cabal latest-prerelease", SetToolTag LatestPrerelease)   , ("set cabal latest-nightly", SetToolTag LatestNightly)   , ("set cabal base-4.18", SetToolTag (Base (PVP {_pComponents = 4 :| [18]})))-  , ("set cabal cabal-3.10", SetToolVersion $(versionQ "cabal-3.10"))+  , ("set cabal cabal-3.10", SetToolVersion $ (`VersionReq` Nothing) $(versionQ "cabal-3.10"))   ] -setHlsCheckList :: [(String, Either SetCommand SetOptions)]-setHlsCheckList = mapSecond (Left . SetHLS . SetOptions)+setHlsCheckList :: [(String, SetCommand)]+setHlsCheckList = mapSecond (SetHLS . SetOptions)   [ ("set hls", SetRecommended)-  , ("set hls 2.0", SetToolVersion $(versionQ "2.0"))+  , ("set hls 2.0", SetToolVersion $ (`VersionReq` Nothing) $(versionQ "2.0"))   , ("set hls next", SetNext)   , ("set hls latest", SetToolTag Latest)-  , ("set hls nightly", SetToolVersion $(versionQ "nightly"))+  , ("set hls nightly", SetToolVersion $ (`VersionReq` Nothing) $(versionQ "nightly"))   , ("set hls recommended", SetToolTag Recommended)-  , ("set hls prerelease", SetToolVersion $(versionQ "prerelease"))+  , ("set hls prerelease", SetToolVersion $ (`VersionReq` Nothing) $(versionQ "prerelease"))   , ("set hls latest-prerelease", SetToolTag LatestPrerelease)   , ("set hls latest-nightly", SetToolTag LatestNightly)   , ("set hls base-4.18", SetToolTag (Base (PVP {_pComponents = 4 :| [18]})))-  , ("set hls hls-2.0", SetToolVersion $(versionQ "hls-2.0"))+  , ("set hls hls-2.0", SetToolVersion $ (`VersionReq` Nothing) $(versionQ "hls-2.0"))   ] -setStackCheckList :: [(String, Either SetCommand SetOptions)]-setStackCheckList = mapSecond (Left . SetStack . SetOptions)+setStackCheckList :: [(String, SetCommand)]+setStackCheckList = mapSecond (SetStack . SetOptions)   [ ("set stack", SetRecommended)-  , ("set stack 2.9", SetToolVersion $(versionQ "2.9"))+  , ("set stack 2.9", SetToolVersion $ (`VersionReq` Nothing) $(versionQ "2.9"))   , ("set stack next", SetNext)   , ("set stack latest", SetToolTag Latest)-  , ("set stack nightly", SetToolVersion $(versionQ "nightly"))+  , ("set stack nightly", SetToolVersion $ (`VersionReq` Nothing) $(versionQ "nightly"))   , ("set stack recommended", SetToolTag Recommended)-  , ("set stack prerelease", SetToolVersion $(versionQ "prerelease"))+  , ("set stack prerelease", SetToolVersion $ (`VersionReq` Nothing) $(versionQ "prerelease"))   , ("set stack latest-prerelease", SetToolTag LatestPrerelease)   , ("set stack latest-nightly", SetToolTag LatestNightly)   , ("set stack base-4.18", SetToolTag (Base (PVP {_pComponents = 4 :| [18]})))-  , ("set stack stack-2.9", SetToolVersion $(versionQ "stack-2.9"))+  , ("set stack stack-2.9", SetToolVersion $ (`VersionReq` Nothing) $(versionQ "stack-2.9"))   ] -setParseWith :: [String] -> IO (Either SetCommand SetOptions)+setParseWith :: [String] -> IO SetCommand setParseWith args = do   Set a <- parseWith args   pure a+
test/optparse-test/WhereisTest.hs view
@@ -14,14 +14,13 @@  whereisCheckList :: [(String, (WhereisOptions, WhereisCommand))] whereisCheckList = concatMap mk-  [ ("whereis ghc", WhereisTool GHC Nothing)-  , ("whereis ghc 9.2.8", WhereisTool GHC (Just $ GHCVersion $ mkTVer $(versionQ "9.2.8")))-  , ("whereis ghc ghc-9.2.8", WhereisTool GHC (Just $ GHCVersion $ GHCTargetVersion (Just "ghc") $(versionQ "9.2.8")))-  , ("whereis ghc latest", WhereisTool GHC (Just $ ToolTag Latest))-  , ("whereis cabal", WhereisTool Cabal Nothing)-  , ("whereis hls", WhereisTool HLS Nothing)-  , ("whereis stack", WhereisTool Stack Nothing)-  , ("whereis ghcup", WhereisTool GHCup Nothing)+  [ ("whereis ghc", WhereisTool ghc Nothing)+  , ("whereis ghc 9.2.8", WhereisTool ghc (Just $ GHCVersion $ toTargetVersionReq'' $(versionQ "9.2.8")))+  , ("whereis ghc latest", WhereisTool ghc (Just $ ToolTag Latest))+  , ("whereis cabal", WhereisTool cabal Nothing)+  , ("whereis hls", WhereisTool hls Nothing)+  , ("whereis stack", WhereisTool stack Nothing)+  , ("whereis ghcup", WhereisTool ghcup Nothing)   , ("whereis basedir", WhereisBaseDir)   , ("whereis bindir", WhereisBinDir)   , ("whereis cachedir", WhereisCacheDir)@@ -30,10 +29,10 @@   ]   where     mk :: (String, WhereisCommand) -> [(String, (WhereisOptions, WhereisCommand))]-    mk (cmd, res) =-      [ (cmd, (WhereisOptions False, res))-      , (cmd <> " -d", (WhereisOptions True, res))-      , (cmd <> " --directory", (WhereisOptions True, res))+    mk (cmd', res) =+      [ (cmd', (WhereisOptions False, res))+      , (cmd' <> " -d", (WhereisOptions True, res))+      , (cmd' <> " --directory", (WhereisOptions True, res))       ]  whereisParseWith :: [String] -> IO (WhereisOptions, WhereisCommand)