diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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)
diff --git a/app/ghcup/Main.hs b/app/ghcup/Main.hs
--- a/app/ghcup/Main.hs
+++ b/app/ghcup/Main.hs
@@ -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)
 
diff --git a/bench/Bench.hs b/bench/Bench.hs
new file mode 100644
--- /dev/null
+++ b/bench/Bench.hs
@@ -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
+              ]
+
diff --git a/bench/BenchList.hs b/bench/BenchList.hs
new file mode 100644
--- /dev/null
+++ b/bench/BenchList.hs
@@ -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)
+
diff --git a/bench/BenchParse.hs b/bench/BenchParse.hs
new file mode 100644
--- /dev/null
+++ b/bench/BenchParse.hs
@@ -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')
+     ]
+
diff --git a/bench/BenchSetup.hs b/bench/BenchSetup.hs
new file mode 100644
--- /dev/null
+++ b/bench/BenchSetup.hs
@@ -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')
+
diff --git a/data/config.yaml b/data/config.yaml
--- a/data/config.yaml
+++ b/data/config.yaml
@@ -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:
diff --git a/ghcup.cabal b/ghcup.cabal
--- a/ghcup.cabal
+++ b/ghcup.cabal
@@ -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
+
diff --git a/lib-opt/GHCup/OptParse.hs b/lib-opt/GHCup/OptParse.hs
--- a/lib-opt/GHCup/OptParse.hs
+++ b/lib-opt/GHCup/OptParse.hs
@@ -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
diff --git a/lib-opt/GHCup/OptParse/ChangeLog.hs b/lib-opt/GHCup/OptParse/ChangeLog.hs
--- a/lib-opt/GHCup/OptParse/ChangeLog.hs
+++ b/lib-opt/GHCup/OptParse/ChangeLog.hs
@@ -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
 
diff --git a/lib-opt/GHCup/OptParse/Common.hs b/lib-opt/GHCup/OptParse/Common.hs
--- a/lib-opt/GHCup/OptParse/Common.hs
+++ b/lib-opt/GHCup/OptParse/Common.hs
@@ -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
diff --git a/lib-opt/GHCup/OptParse/Compile.hs b/lib-opt/GHCup/OptParse/Compile.hs
--- a/lib-opt/GHCup/OptParse/Compile.hs
+++ b/lib-opt/GHCup/OptParse/Compile.hs
@@ -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
diff --git a/lib-opt/GHCup/OptParse/Config.hs b/lib-opt/GHCup/OptParse/Config.hs
--- a/lib-opt/GHCup/OptParse/Config.hs
+++ b/lib-opt/GHCup/OptParse/Config.hs
@@ -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
diff --git a/lib-opt/GHCup/OptParse/DInfo.hs b/lib-opt/GHCup/OptParse/DInfo.hs
deleted file mode 100644
--- a/lib-opt/GHCup/OptParse/DInfo.hs
+++ /dev/null
@@ -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
diff --git a/lib-opt/GHCup/OptParse/DebugInfo.hs b/lib-opt/GHCup/OptParse/DebugInfo.hs
new file mode 100644
--- /dev/null
+++ b/lib-opt/GHCup/OptParse/DebugInfo.hs
@@ -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)
diff --git a/lib-opt/GHCup/OptParse/GC.hs b/lib-opt/GHCup/OptParse/GC.hs
--- a/lib-opt/GHCup/OptParse/GC.hs
+++ b/lib-opt/GHCup/OptParse/GC.hs
@@ -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
diff --git a/lib-opt/GHCup/OptParse/Generate.hs b/lib-opt/GHCup/OptParse/Generate.hs
new file mode 100644
--- /dev/null
+++ b/lib-opt/GHCup/OptParse/Generate.hs
@@ -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
diff --git a/lib-opt/GHCup/OptParse/HealthCheck.hs b/lib-opt/GHCup/OptParse/HealthCheck.hs
new file mode 100644
--- /dev/null
+++ b/lib-opt/GHCup/OptParse/HealthCheck.hs
@@ -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)
+
diff --git a/lib-opt/GHCup/OptParse/Install.hs b/lib-opt/GHCup/OptParse/Install.hs
--- a/lib-opt/GHCup/OptParse/Install.hs
+++ b/lib-opt/GHCup/OptParse/Install.hs
@@ -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
diff --git a/lib-opt/GHCup/OptParse/List.hs b/lib-opt/GHCup/OptParse/List.hs
--- a/lib-opt/GHCup/OptParse/List.hs
+++ b/lib-opt/GHCup/OptParse/List.hs
@@ -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)
diff --git a/lib-opt/GHCup/OptParse/Nuke.hs b/lib-opt/GHCup/OptParse/Nuke.hs
--- a/lib-opt/GHCup/OptParse/Nuke.hs
+++ b/lib-opt/GHCup/OptParse/Nuke.hs
@@ -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
diff --git a/lib-opt/GHCup/OptParse/Prefetch.hs b/lib-opt/GHCup/OptParse/Prefetch.hs
--- a/lib-opt/GHCup/OptParse/Prefetch.hs
+++ b/lib-opt/GHCup/OptParse/Prefetch.hs
@@ -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
diff --git a/lib-opt/GHCup/OptParse/Reset.hs b/lib-opt/GHCup/OptParse/Reset.hs
new file mode 100644
--- /dev/null
+++ b/lib-opt/GHCup/OptParse/Reset.hs
@@ -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 }
+
+
diff --git a/lib-opt/GHCup/OptParse/Rm.hs b/lib-opt/GHCup/OptParse/Rm.hs
--- a/lib-opt/GHCup/OptParse/Rm.hs
+++ b/lib-opt/GHCup/OptParse/Rm.hs
@@ -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
diff --git a/lib-opt/GHCup/OptParse/Run.hs b/lib-opt/GHCup/OptParse/Run.hs
--- a/lib-opt/GHCup/OptParse/Run.hs
+++ b/lib-opt/GHCup/OptParse/Run.hs
@@ -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)
diff --git a/lib-opt/GHCup/OptParse/Set.hs b/lib-opt/GHCup/OptParse/Set.hs
--- a/lib-opt/GHCup/OptParse/Set.hs
+++ b/lib-opt/GHCup/OptParse/Set.hs
@@ -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
diff --git a/lib-opt/GHCup/OptParse/Test.hs b/lib-opt/GHCup/OptParse/Test.hs
--- a/lib-opt/GHCup/OptParse/Test.hs
+++ b/lib-opt/GHCup/OptParse/Test.hs
@@ -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
diff --git a/lib-opt/GHCup/OptParse/ToolRequirements.hs b/lib-opt/GHCup/OptParse/ToolRequirements.hs
--- a/lib-opt/GHCup/OptParse/ToolRequirements.hs
+++ b/lib-opt/GHCup/OptParse/ToolRequirements.hs
@@ -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
diff --git a/lib-opt/GHCup/OptParse/UnSet.hs b/lib-opt/GHCup/OptParse/UnSet.hs
--- a/lib-opt/GHCup/OptParse/UnSet.hs
+++ b/lib-opt/GHCup/OptParse/UnSet.hs
@@ -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
+
+
diff --git a/lib-opt/GHCup/OptParse/Upgrade.hs b/lib-opt/GHCup/OptParse/Upgrade.hs
--- a/lib-opt/GHCup/OptParse/Upgrade.hs
+++ b/lib-opt/GHCup/OptParse/Upgrade.hs
@@ -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)
diff --git a/lib-opt/GHCup/OptParse/Whereis.hs b/lib-opt/GHCup/OptParse/Whereis.hs
--- a/lib-opt/GHCup/OptParse/Whereis.hs
+++ b/lib-opt/GHCup/OptParse/Whereis.hs
@@ -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'
diff --git a/lib-tui/GHCup/Brick/Actions.hs b/lib-tui/GHCup/Brick/Actions.hs
--- a/lib-tui/GHCup/Brick/Actions.hs
+++ b/lib-tui/GHCup/Brick/Actions.hs
@@ -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)
diff --git a/lib-tui/GHCup/Brick/App.hs b/lib-tui/GHCup/Brick/App.hs
--- a/lib-tui/GHCup/Brick/App.hs
+++ b/lib-tui/GHCup/Brick/App.hs
@@ -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
diff --git a/lib-tui/GHCup/Brick/Attributes.hs b/lib-tui/GHCup/Brick/Attributes.hs
--- a/lib-tui/GHCup/Brick/Attributes.hs
+++ b/lib-tui/GHCup/Brick/Attributes.hs
@@ -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)
   ]
diff --git a/lib-tui/GHCup/Brick/BrickState.hs b/lib-tui/GHCup/Brick/BrickState.hs
--- a/lib-tui/GHCup/Brick/BrickState.hs
+++ b/lib-tui/GHCup/Brick/BrickState.hs
@@ -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
 
diff --git a/lib-tui/GHCup/Brick/Common.hs b/lib-tui/GHCup/Brick/Common.hs
--- a/lib-tui/GHCup/Brick/Common.hs
+++ b/lib-tui/GHCup/Brick/Common.hs
@@ -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
 
diff --git a/lib-tui/GHCup/Brick/Widgets/KeyInfo.hs b/lib-tui/GHCup/Brick/Widgets/KeyInfo.hs
--- a/lib-tui/GHCup/Brick/Widgets/KeyInfo.hs
+++ b/lib-tui/GHCup/Brick/Widgets/KeyInfo.hs
@@ -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 "
diff --git a/lib-tui/GHCup/Brick/Widgets/Menu.hs b/lib-tui/GHCup/Brick/Widgets/Menu.hs
--- a/lib-tui/GHCup/Brick/Widgets/Menu.hs
+++ b/lib-tui/GHCup/Brick/Widgets/Menu.hs
@@ -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)
 
diff --git a/lib-tui/GHCup/Brick/Widgets/Menus/AdvanceInstall.hs b/lib-tui/GHCup/Brick/Widgets/Menus/AdvanceInstall.hs
deleted file mode 100644
--- a/lib-tui/GHCup/Brick/Widgets/Menus/AdvanceInstall.hs
+++ /dev/null
@@ -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
diff --git a/lib-tui/GHCup/Brick/Widgets/Menus/AdvancedInstall.hs b/lib-tui/GHCup/Brick/Widgets/Menus/AdvancedInstall.hs
new file mode 100644
--- /dev/null
+++ b/lib-tui/GHCup/Brick/Widgets/Menus/AdvancedInstall.hs
@@ -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
diff --git a/lib-tui/GHCup/Brick/Widgets/Menus/CompileGHC.hs b/lib-tui/GHCup/Brick/Widgets/Menus/CompileGHC.hs
--- a/lib-tui/GHCup/Brick/Widgets/Menus/CompileGHC.hs
+++ b/lib-tui/GHCup/Brick/Widgets/Menus/CompileGHC.hs
@@ -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 = [
diff --git a/lib-tui/GHCup/Brick/Widgets/Menus/CompileHLS.hs b/lib-tui/GHCup/Brick/Widgets/Menus/CompileHLS.hs
--- a/lib-tui/GHCup/Brick/Widgets/Menus/CompileHLS.hs
+++ b/lib-tui/GHCup/Brick/Widgets/Menus/CompileHLS.hs
@@ -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)"
diff --git a/lib-tui/GHCup/Brick/Widgets/Menus/Context.hs b/lib-tui/GHCup/Brick/Widgets/Menus/Context.hs
--- a/lib-tui/GHCup/Brick/Widgets/Menus/Context.hs
+++ b/lib-tui/GHCup/Brick/Widgets/Menus/Context.hs
@@ -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
diff --git a/lib-tui/GHCup/Brick/Widgets/Navigation.hs b/lib-tui/GHCup/Brick/Widgets/Navigation.hs
--- a/lib-tui/GHCup/Brick/Widgets/Navigation.hs
+++ b/lib-tui/GHCup/Brick/Widgets/Navigation.hs
@@ -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
diff --git a/lib-tui/GHCup/Brick/Widgets/SectionList.hs b/lib-tui/GHCup/Brick/Widgets/SectionList.hs
deleted file mode 100644
--- a/lib-tui/GHCup/Brick/Widgets/SectionList.hs
+++ /dev/null
@@ -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
diff --git a/lib-tui/GHCup/Brick/Widgets/ToolInfo.hs b/lib-tui/GHCup/Brick/Widgets/ToolInfo.hs
new file mode 100644
--- /dev/null
+++ b/lib-tui/GHCup/Brick/Widgets/ToolInfo.hs
@@ -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"]
diff --git a/lib-tui/GHCup/Brick/Widgets/Tutorial.hs b/lib-tui/GHCup/Brick/Widgets/Tutorial.hs
--- a/lib-tui/GHCup/Brick/Widgets/Tutorial.hs
+++ b/lib-tui/GHCup/Brick/Widgets/Tutorial.hs
@@ -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")
diff --git a/lib-tui/GHCup/BrickMain.hs b/lib-tui/GHCup/BrickMain.hs
--- a/lib-tui/GHCup/BrickMain.hs
+++ b/lib-tui/GHCup/BrickMain.hs
@@ -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
diff --git a/lib/GHCup.hs b/lib/GHCup.hs
deleted file mode 100644
--- a/lib/GHCup.hs
+++ /dev/null
@@ -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
-
-
diff --git a/lib/GHCup/Builder.hs b/lib/GHCup/Builder.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Builder.hs
@@ -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
+
diff --git a/lib/GHCup/Cabal.hs b/lib/GHCup/Cabal.hs
deleted file mode 100644
--- a/lib/GHCup/Cabal.hs
+++ /dev/null
@@ -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)
diff --git a/lib/GHCup/CabalConfig.hs b/lib/GHCup/CabalConfig.hs
--- a/lib/GHCup/CabalConfig.hs
+++ b/lib/GHCup/CabalConfig.hs
@@ -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
 
 
 -------------------------------------------------------------------------------
diff --git a/lib/GHCup/Command/Compile/GHC.hs b/lib/GHCup/Command/Compile/GHC.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Command/Compile/GHC.hs
@@ -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
+
diff --git a/lib/GHCup/Command/Compile/HLS.hs b/lib/GHCup/Command/Compile/HLS.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Command/Compile/HLS.hs
@@ -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
diff --git a/lib/GHCup/Command/DebugInfo.hs b/lib/GHCup/Command/DebugInfo.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Command/DebugInfo.hs
@@ -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 { .. }
diff --git a/lib/GHCup/Command/GC.hs b/lib/GHCup/Command/GC.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Command/GC.hs
@@ -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
+
diff --git a/lib/GHCup/Command/HealthCheck.hs b/lib/GHCup/Command/HealthCheck.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Command/HealthCheck.hs
@@ -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
+
diff --git a/lib/GHCup/Command/Install.hs b/lib/GHCup/Command/Install.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Command/Install.hs
@@ -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 ()
diff --git a/lib/GHCup/Command/Install/LowLevel.hs b/lib/GHCup/Command/Install/LowLevel.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Command/Install/LowLevel.hs
@@ -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
+
diff --git a/lib/GHCup/Command/List.hs b/lib/GHCup/Command/List.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Command/List.hs
@@ -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
+
diff --git a/lib/GHCup/Command/Nuke.hs b/lib/GHCup/Command/Nuke.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Command/Nuke.hs
@@ -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)
+
+
diff --git a/lib/GHCup/Command/Prefetch.hs b/lib/GHCup/Command/Prefetch.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Command/Prefetch.hs
@@ -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
+
diff --git a/lib/GHCup/Command/Rm.hs b/lib/GHCup/Command/Rm.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Command/Rm.hs
@@ -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."
diff --git a/lib/GHCup/Command/Set.hs b/lib/GHCup/Command/Set.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Command/Set.hs
@@ -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
+
diff --git a/lib/GHCup/Command/Test/GHC.hs b/lib/GHCup/Command/Test/GHC.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Command/Test/GHC.hs
@@ -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 ()
diff --git a/lib/GHCup/Command/Upgrade.hs b/lib/GHCup/Command/Upgrade.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Command/Upgrade.hs
@@ -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
+
diff --git a/lib/GHCup/Command/Whereis.hs b/lib/GHCup/Command/Whereis.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Command/Whereis.hs
@@ -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 ""
+
diff --git a/lib/GHCup/Compat/Pager.hs b/lib/GHCup/Compat/Pager.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Compat/Pager.hs
@@ -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
+
diff --git a/lib/GHCup/Compat/Terminal.hs b/lib/GHCup/Compat/Terminal.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Compat/Terminal.hs
@@ -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
diff --git a/lib/GHCup/Download.hs b/lib/GHCup/Download.hs
--- a/lib/GHCup/Download.hs
+++ b/lib/GHCup/Download.hs
@@ -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
+
diff --git a/lib/GHCup/Download/IOStreams.hs b/lib/GHCup/Download/IOStreams.hs
--- a/lib/GHCup/Download/IOStreams.hs
+++ b/lib/GHCup/Download/IOStreams.hs
@@ -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)
diff --git a/lib/GHCup/Download/Utils.hs b/lib/GHCup/Download/Utils.hs
deleted file mode 100644
--- a/lib/GHCup/Download/Utils.hs
+++ /dev/null
@@ -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
-
diff --git a/lib/GHCup/Errors.hs b/lib/GHCup/Errors.hs
--- a/lib/GHCup/Errors.hs
+++ b/lib/GHCup/Errors.hs
@@ -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
diff --git a/lib/GHCup/GHC.hs b/lib/GHCup/GHC.hs
deleted file mode 100644
--- a/lib/GHCup/GHC.hs
+++ /dev/null
@@ -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
-
diff --git a/lib/GHCup/HLS.hs b/lib/GHCup/HLS.hs
deleted file mode 100644
--- a/lib/GHCup/HLS.hs
+++ /dev/null
@@ -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
diff --git a/lib/GHCup/Hardcoded/URLs.hs b/lib/GHCup/Hardcoded/URLs.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Hardcoded/URLs.hs
@@ -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|]
+
diff --git a/lib/GHCup/Hardcoded/Version.hs b/lib/GHCup/Hardcoded/Version.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Hardcoded/Version.hs
@@ -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
+
diff --git a/lib/GHCup/Input/Parsers.hs b/lib/GHCup/Input/Parsers.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Input/Parsers.hs
@@ -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
+
diff --git a/lib/GHCup/Input/Parsers/URI.hs b/lib/GHCup/Input/Parsers/URI.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Input/Parsers/URI.hs
@@ -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
diff --git a/lib/GHCup/Input/Prompts.hs b/lib/GHCup/Input/Prompts.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Input/Prompts.hs
@@ -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
diff --git a/lib/GHCup/Input/SymlinkSpec.hs b/lib/GHCup/Input/SymlinkSpec.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Input/SymlinkSpec.hs
@@ -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
+
diff --git a/lib/GHCup/Legacy/Cabal.hs b/lib/GHCup/Legacy/Cabal.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Legacy/Cabal.hs
@@ -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)
diff --git a/lib/GHCup/Legacy/HLS.hs b/lib/GHCup/Legacy/HLS.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Legacy/HLS.hs
@@ -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 ()
+
+
diff --git a/lib/GHCup/Legacy/Stack.hs b/lib/GHCup/Legacy/Stack.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Legacy/Stack.hs
@@ -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)
diff --git a/lib/GHCup/Legacy/Utils.hs b/lib/GHCup/Legacy/Utils.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Legacy/Utils.hs
@@ -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
diff --git a/lib/GHCup/List.hs b/lib/GHCup/List.hs
deleted file mode 100644
--- a/lib/GHCup/List.hs
+++ /dev/null
@@ -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
-
diff --git a/lib/GHCup/PlanJson.hs b/lib/GHCup/PlanJson.hs
--- a/lib/GHCup/PlanJson.hs
+++ b/lib/GHCup/PlanJson.hs
@@ -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
diff --git a/lib/GHCup/Platform.hs b/lib/GHCup/Platform.hs
deleted file mode 100644
--- a/lib/GHCup/Platform.hs
+++ /dev/null
@@ -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'
-
diff --git a/lib/GHCup/Prelude.hs b/lib/GHCup/Prelude.hs
--- a/lib/GHCup/Prelude.hs
+++ b/lib/GHCup/Prelude.hs
@@ -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
diff --git a/lib/GHCup/Prelude/Attoparsec.hs b/lib/GHCup/Prelude/Attoparsec.hs
--- a/lib/GHCup/Prelude/Attoparsec.hs
+++ b/lib/GHCup/Prelude/Attoparsec.hs
@@ -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
 
 
 
diff --git a/lib/GHCup/Prelude/File.hs b/lib/GHCup/Prelude/File.hs
--- a/lib/GHCup/Prelude/File.hs
+++ b/lib/GHCup/Prelude/File.hs
@@ -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
diff --git a/lib/GHCup/Prelude/File/Posix.hs b/lib/GHCup/Prelude/File/Posix.hs
--- a/lib/GHCup/Prelude/File/Posix.hs
+++ b/lib/GHCup/Prelude/File/Posix.hs
@@ -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
 
 
diff --git a/lib/GHCup/Prelude/File/Search.hs b/lib/GHCup/Prelude/File/Search.hs
--- a/lib/GHCup/Prelude/File/Search.hs
+++ b/lib/GHCup/Prelude/File/Search.hs
@@ -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
diff --git a/lib/GHCup/Prelude/File/Windows.hs b/lib/GHCup/Prelude/File/Windows.hs
--- a/lib/GHCup/Prelude/File/Windows.hs
+++ b/lib/GHCup/Prelude/File/Windows.hs
@@ -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
diff --git a/lib/GHCup/Prelude/Internal.hs b/lib/GHCup/Prelude/Internal.hs
--- a/lib/GHCup/Prelude/Internal.hs
+++ b/lib/GHCup/Prelude/Internal.hs
@@ -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
+
diff --git a/lib/GHCup/Prelude/JSON.hs b/lib/GHCup/Prelude/JSON.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Prelude/JSON.hs
@@ -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
+
diff --git a/lib/GHCup/Prelude/Logger.hs b/lib/GHCup/Prelude/Logger.hs
--- a/lib/GHCup/Prelude/Logger.hs
+++ b/lib/GHCup/Prelude/Logger.hs
@@ -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
 
 
 
diff --git a/lib/GHCup/Prelude/Logger/Internal.hs b/lib/GHCup/Prelude/Logger/Internal.hs
--- a/lib/GHCup/Prelude/Logger/Internal.hs
+++ b/lib/GHCup/Prelude/Logger/Internal.hs
@@ -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:"
diff --git a/lib/GHCup/Prelude/MegaParsec.hs b/lib/GHCup/Prelude/MegaParsec.hs
--- a/lib/GHCup/Prelude/MegaParsec.hs
+++ b/lib/GHCup/Prelude/MegaParsec.hs
@@ -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'
+
diff --git a/lib/GHCup/Prelude/Posix.hs b/lib/GHCup/Prelude/Posix.hs
--- a/lib/GHCup/Prelude/Posix.hs
+++ b/lib/GHCup/Prelude/Posix.hs
@@ -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.
 --
diff --git a/lib/GHCup/Prelude/Process/Posix.hs b/lib/GHCup/Prelude/Process/Posix.hs
--- a/lib/GHCup/Prelude/Process/Posix.hs
+++ b/lib/GHCup/Prelude/Process/Posix.hs
@@ -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
diff --git a/lib/GHCup/Prelude/Process/Windows.hs b/lib/GHCup/Prelude/Process/Windows.hs
--- a/lib/GHCup/Prelude/Process/Windows.hs
+++ b/lib/GHCup/Prelude/Process/Windows.hs
@@ -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
diff --git a/lib/GHCup/Prelude/String/QQ.hs b/lib/GHCup/Prelude/String/QQ.hs
--- a/lib/GHCup/Prelude/String/QQ.hs
+++ b/lib/GHCup/Prelude/String/QQ.hs
@@ -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")
diff --git a/lib/GHCup/Prelude/Version.hs b/lib/GHCup/Prelude/Version.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Prelude/Version.hs
@@ -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
+
diff --git a/lib/GHCup/Prelude/Version/QQ.hs b/lib/GHCup/Prelude/Version/QQ.hs
--- a/lib/GHCup/Prelude/Version/QQ.hs
+++ b/lib/GHCup/Prelude/Version/QQ.hs
@@ -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)
diff --git a/lib/GHCup/Prelude/Windows.hs b/lib/GHCup/Prelude/Windows.hs
--- a/lib/GHCup/Prelude/Windows.hs
+++ b/lib/GHCup/Prelude/Windows.hs
@@ -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.
 --
diff --git a/lib/GHCup/Prompts.hs b/lib/GHCup/Prompts.hs
deleted file mode 100644
--- a/lib/GHCup/Prompts.hs
+++ /dev/null
@@ -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
diff --git a/lib/GHCup/Query.hs b/lib/GHCup/Query.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Query.hs
@@ -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
diff --git a/lib/GHCup/Query/DB.hs b/lib/GHCup/Query/DB.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Query/DB.hs
@@ -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
+
diff --git a/lib/GHCup/Query/DB/HLS.hs b/lib/GHCup/Query/DB/HLS.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Query/DB/HLS.hs
@@ -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
+
diff --git a/lib/GHCup/Query/GHCupDirs.hs b/lib/GHCup/Query/GHCupDirs.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Query/GHCupDirs.hs
@@ -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
+
diff --git a/lib/GHCup/Query/GHCupDirs.hs-boot b/lib/GHCup/Query/GHCupDirs.hs-boot
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Query/GHCupDirs.hs-boot
@@ -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 ()
+
diff --git a/lib/GHCup/Query/Metadata.hs b/lib/GHCup/Query/Metadata.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Query/Metadata.hs
@@ -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)
+
diff --git a/lib/GHCup/Query/Symlink.hs b/lib/GHCup/Query/Symlink.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Query/Symlink.hs
@@ -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
diff --git a/lib/GHCup/Query/System.hs b/lib/GHCup/Query/System.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Query/System.hs
@@ -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'
+
diff --git a/lib/GHCup/Requirements.hs b/lib/GHCup/Requirements.hs
deleted file mode 100644
--- a/lib/GHCup/Requirements.hs
+++ /dev/null
@@ -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 ""
diff --git a/lib/GHCup/Setup.hs b/lib/GHCup/Setup.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Setup.hs
@@ -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 ()
diff --git a/lib/GHCup/Stack.hs b/lib/GHCup/Stack.hs
deleted file mode 100644
--- a/lib/GHCup/Stack.hs
+++ /dev/null
@@ -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)
diff --git a/lib/GHCup/System/Cmd.hs b/lib/GHCup/System/Cmd.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/System/Cmd.hs
@@ -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
diff --git a/lib/GHCup/System/Directory.hs b/lib/GHCup/System/Directory.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/System/Directory.hs
@@ -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
+    )
diff --git a/lib/GHCup/Types.hs b/lib/GHCup/Types.hs
--- a/lib/GHCup/Types.hs
+++ b/lib/GHCup/Types.hs
@@ -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)
 
diff --git a/lib/GHCup/Types/Dhall.hs b/lib/GHCup/Types/Dhall.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Types/Dhall.hs
@@ -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
diff --git a/lib/GHCup/Types/JSON.hs b/lib/GHCup/Types/JSON.hs
--- a/lib/GHCup/Types/JSON.hs
+++ b/lib/GHCup/Types/JSON.hs
@@ -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
diff --git a/lib/GHCup/Types/JSON/MapIgnoreUnknownKeys.hs b/lib/GHCup/Types/JSON/MapIgnoreUnknownKeys.hs
--- a/lib/GHCup/Types/JSON/MapIgnoreUnknownKeys.hs
+++ b/lib/GHCup/Types/JSON/MapIgnoreUnknownKeys.hs
@@ -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
diff --git a/lib/GHCup/Types/JSON/Utils.hs b/lib/GHCup/Types/JSON/Utils.hs
--- a/lib/GHCup/Types/JSON/Utils.hs
+++ b/lib/GHCup/Types/JSON/Utils.hs
@@ -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 .:)
+
diff --git a/lib/GHCup/Types/JSON/Versions.hs b/lib/GHCup/Types/JSON/Versions.hs
--- a/lib/GHCup/Types/JSON/Versions.hs
+++ b/lib/GHCup/Types/JSON/Versions.hs
@@ -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
diff --git a/lib/GHCup/Types/Optics.hs b/lib/GHCup/Types/Optics.hs
--- a/lib/GHCup/Types/Optics.hs
+++ b/lib/GHCup/Types/Optics.hs
@@ -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)
diff --git a/lib/GHCup/Types/Stack.hs b/lib/GHCup/Types/Stack.hs
--- a/lib/GHCup/Types/Stack.hs
+++ b/lib/GHCup/Types/Stack.hs
@@ -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
 
diff --git a/lib/GHCup/Types/Tar.hs b/lib/GHCup/Types/Tar.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Types/Tar.hs
@@ -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
diff --git a/lib/GHCup/Unpack.hs b/lib/GHCup/Unpack.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Unpack.hs
@@ -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
+
diff --git a/lib/GHCup/Utils.hs b/lib/GHCup/Utils.hs
deleted file mode 100644
--- a/lib/GHCup/Utils.hs
+++ /dev/null
@@ -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
diff --git a/lib/GHCup/Utils/Dirs.hs b/lib/GHCup/Utils/Dirs.hs
deleted file mode 100644
--- a/lib/GHCup/Utils/Dirs.hs
+++ /dev/null
@@ -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
-
-
-
-
diff --git a/lib/GHCup/Utils/Dirs.hs-boot b/lib/GHCup/Utils/Dirs.hs-boot
deleted file mode 100644
--- a/lib/GHCup/Utils/Dirs.hs-boot
+++ /dev/null
@@ -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 ()
-
diff --git a/lib/GHCup/Utils/Output.hs b/lib/GHCup/Utils/Output.hs
deleted file mode 100644
--- a/lib/GHCup/Utils/Output.hs
+++ /dev/null
@@ -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
diff --git a/lib/GHCup/Utils/Pager.hs b/lib/GHCup/Utils/Pager.hs
deleted file mode 100644
--- a/lib/GHCup/Utils/Pager.hs
+++ /dev/null
@@ -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
-
diff --git a/lib/GHCup/Utils/Parsers.hs b/lib/GHCup/Utils/Parsers.hs
deleted file mode 100644
--- a/lib/GHCup/Utils/Parsers.hs
+++ /dev/null
@@ -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
-
diff --git a/lib/GHCup/Utils/Tar.hs b/lib/GHCup/Utils/Tar.hs
deleted file mode 100644
--- a/lib/GHCup/Utils/Tar.hs
+++ /dev/null
@@ -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
-
diff --git a/lib/GHCup/Utils/Tar/Types.hs b/lib/GHCup/Utils/Tar/Types.hs
deleted file mode 100644
--- a/lib/GHCup/Utils/Tar/Types.hs
+++ /dev/null
@@ -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
diff --git a/lib/GHCup/Utils/URI.hs b/lib/GHCup/Utils/URI.hs
deleted file mode 100644
--- a/lib/GHCup/Utils/URI.hs
+++ /dev/null
@@ -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
diff --git a/lib/GHCup/Version.hs b/lib/GHCup/Version.hs
deleted file mode 100644
--- a/lib/GHCup/Version.hs
+++ /dev/null
@@ -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|]
diff --git a/lib/GHCup/Warnings.hs b/lib/GHCup/Warnings.hs
new file mode 100644
--- /dev/null
+++ b/lib/GHCup/Warnings.hs
@@ -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 ()
+
diff --git a/scripts/bootstrap/bootstrap-haskell b/scripts/bootstrap/bootstrap-haskell
--- a/scripts/bootstrap/bootstrap-haskell
+++ b/scripts/bootstrap/bootstrap-haskell
@@ -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
diff --git a/scripts/bootstrap/bootstrap-haskell.ps1 b/scripts/bootstrap/bootstrap-haskell.ps1
--- a/scripts/bootstrap/bootstrap-haskell.ps1
+++ b/scripts/bootstrap/bootstrap-haskell.ps1
@@ -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
 }
 
diff --git a/test/ghcup-test/GHCup/ArbitraryTypes.hs b/test/ghcup-test/GHCup/ArbitraryTypes.hs
--- a/test/ghcup-test/GHCup/ArbitraryTypes.hs
+++ b/test/ghcup-test/GHCup/ArbitraryTypes.hs
@@ -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
 
 
diff --git a/test/ghcup-test/GHCup/ParserSpec.hs b/test/ghcup-test/GHCup/ParserSpec.hs
--- a/test/ghcup-test/GHCup/ParserSpec.hs
+++ b/test/ghcup-test/GHCup/ParserSpec.hs
@@ -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}}
diff --git a/test/ghcup-test/GHCup/Prelude/File/Posix/TraversalsSpec.hs b/test/ghcup-test/GHCup/Prelude/File/Posix/TraversalsSpec.hs
--- a/test/ghcup-test/GHCup/Prelude/File/Posix/TraversalsSpec.hs
+++ b/test/ghcup-test/GHCup/Prelude/File/Posix/TraversalsSpec.hs
@@ -8,7 +8,6 @@
 
 import           Control.Monad.IO.Class (liftIO)
 import           Data.List
-import           System.Posix.Directory
 import           Unsafe.Coerce
 #endif
 
diff --git a/test/ghcup-test/GHCup/Types/JSONSpec.hs b/test/ghcup-test/GHCup/Types/JSONSpec.hs
--- a/test/ghcup-test/GHCup/Types/JSONSpec.hs
+++ b/test/ghcup-test/GHCup/Types/JSONSpec.hs
@@ -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
diff --git a/test/ghcup-test/golden/unix/GHCupInfo.json b/test/ghcup-test/golden/unix/GHCupInfo.json
--- a/test/ghcup-test/golden/unix/GHCupInfo.json
+++ b/test/ghcup-test/golden/unix/GHCupInfo.json
@@ -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": "YY->\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": [
-                                            "K9O",
-                                            "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": "6WpZ󴠩"
-                                        },
-                                        "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
 }
diff --git a/test/optparse-test/ChangeLogTest.hs b/test/optparse-test/ChangeLogTest.hs
--- a/test/optparse-test/ChangeLogTest.hs
+++ b/test/optparse-test/ChangeLogTest.hs
@@ -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"))))
diff --git a/test/optparse-test/CompileTest.hs b/test/optparse-test/CompileTest.hs
--- a/test/optparse-test/CompileTest.hs
+++ b/test/optparse-test/CompileTest.hs
@@ -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
diff --git a/test/optparse-test/ConfigTest.hs b/test/optparse-test/ConfigTest.hs
--- a/test/optparse-test/ConfigTest.hs
+++ b/test/optparse-test/ConfigTest.hs
@@ -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
diff --git a/test/optparse-test/InstallTest.hs b/test/optparse-test/InstallTest.hs
--- a/test/optparse-test/InstallTest.hs
+++ b/test/optparse-test/InstallTest.hs
@@ -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
diff --git a/test/optparse-test/ListTest.hs b/test/optparse-test/ListTest.hs
--- a/test/optparse-test/ListTest.hs
+++ b/test/optparse-test/ListTest.hs
@@ -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
diff --git a/test/optparse-test/RmTest.hs b/test/optparse-test/RmTest.hs
--- a/test/optparse-test/RmTest.hs
+++ b/test/optparse-test/RmTest.hs
@@ -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
diff --git a/test/optparse-test/RunTest.hs b/test/optparse-test/RunTest.hs
--- a/test/optparse-test/RunTest.hs
+++ b/test/optparse-test/RunTest.hs
@@ -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
           }
     )
diff --git a/test/optparse-test/SetTest.hs b/test/optparse-test/SetTest.hs
--- a/test/optparse-test/SetTest.hs
+++ b/test/optparse-test/SetTest.hs
@@ -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
+
diff --git a/test/optparse-test/WhereisTest.hs b/test/optparse-test/WhereisTest.hs
--- a/test/optparse-test/WhereisTest.hs
+++ b/test/optparse-test/WhereisTest.hs
@@ -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)
