Compare commits

..

1 Commits

Author SHA1 Message Date
d5483facdc Add ansi terminal skeleton 2023-01-05 21:41:00 +08:00
14 changed files with 548 additions and 1203 deletions

18
app/ghcup/AnsiMain.hs Normal file
View File

@@ -0,0 +1,18 @@
module AnsiMain where
import GHCup
import GHCup.Download
import GHCup.Errors
import GHCup.Types.Optics ( getDirs )
import GHCup.Types hiding ( LeanAppState(..) )
import GHCup.Utils
import GHCup.Prelude ( decUTF8Safe )
import GHCup.Prelude.File
import GHCup.Prelude.Logger
import GHCup.Prelude.Process
ansiMain :: AppState
-> IO ()
ansiMain s = do
putStrLn "ansi terminal"
pure ()

View File

@@ -8,7 +8,6 @@
module GHCup.OptParse (
module GHCup.OptParse.Common
, module GHCup.OptParse.Install
, module GHCup.OptParse.Test
, module GHCup.OptParse.Set
, module GHCup.OptParse.UnSet
, module GHCup.OptParse.Rm
@@ -32,7 +31,6 @@ module GHCup.OptParse (
import GHCup.OptParse.Common
import GHCup.OptParse.Install
import GHCup.OptParse.Test
import GHCup.OptParse.Set
import GHCup.OptParse.UnSet
import GHCup.OptParse.Rm
@@ -89,7 +87,6 @@ data Options = Options
data Command
= Install (Either InstallCommand InstallOptions)
| Test TestCommand
| InstallCabalLegacy InstallOptions
| Set (Either SetCommand SetOptions)
| UnSet UnsetCommand
@@ -107,6 +104,9 @@ data Command
| Nuke
#if defined(BRICK)
| Interactive
#endif
#if defined(ANSI)
| InteractiveAnsi
#endif
| Prefetch PrefetchCommand
| GC GCOptions
@@ -187,8 +187,19 @@ opts =
com :: Parser Command
com =
subparser
#if defined(BRICK)
#if defined(ANSI)
( command
"tui-ansi"
( (\_ -> InteractiveAnsi)
<$> info
helper
( progDesc "Start the interactive GHCup UI (ansi)"
)
)
<>
#endif
#if defined(BRICK)
command
"tui"
( (\_ -> Interactive)
<$> info
@@ -198,7 +209,7 @@ com =
)
<> command
#else
( command
command
#endif
"install"
( Install
@@ -208,14 +219,6 @@ com =
<> footerDoc (Just $ text installToolFooter)
)
)
<> command
"test"
(info
(Test <$> testParser <**> helper)
( progDesc "Run tests for a tool (if any) [EXPERIMENTAL!]"
<> footerDoc (Just $ text testFooter)
)
)
<> command
"set"
(info

View File

@@ -254,7 +254,7 @@ run RunOptions{..} runAppState leanAppstate runLogger = do
liftIO $ putStr tmp
pure ExitSuccess
(cmd:args) -> do
newEnv <- liftIO $ addToPath tmp runAppendPATH
newEnv <- liftIO $ addToPath tmp
#ifndef IS_WINDOWS
void $ liftIO $ SPP.executeFile cmd True args (Just newEnv)
pure ExitSuccess
@@ -441,6 +441,17 @@ run RunOptions{..} runAppState leanAppstate runLogger = do
liftE $ setHLS v SetHLS_XYZ (Just tmp)
liftE $ setHLS v SetHLSOnly (Just tmp)
addToPath path = do
cEnv <- Map.fromList <$> getEnvironment
let paths = ["PATH", "Path"]
curPaths = (\x -> maybe [] splitSearchPath (Map.lookup x cEnv)) =<< paths
newPath = intercalate [searchPathSeparator] (if runAppendPATH then (curPaths ++ [path]) else (path : curPaths))
envWithoutPath = foldr (\x y -> Map.delete x y) cEnv paths
pathVar = if isWindows then "Path" else "PATH"
envWithNewPath = Map.toList $ Map.insert pathVar newPath envWithoutPath
liftIO $ setEnv pathVar newPath
return envWithNewPath
createTmpDir :: ( MonadUnliftIO m
, MonadCatch m
, MonadThrow m

View File

@@ -1,188 +0,0 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE TypeOperators #-}
module GHCup.OptParse.Test where
import GHCup.OptParse.Common
import GHCup
import GHCup.Errors
import GHCup.Types
import GHCup.Utils.Dirs
import GHCup.Prelude.Logger
import GHCup.Prelude.String.QQ
import Codec.Archive
#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 Haskus.Utils.Variant.Excepts
import Options.Applicative hiding ( style )
import Options.Applicative.Help.Pretty ( text )
import Prelude hiding ( appendFile )
import System.Exit
import URI.ByteString hiding ( uriParser )
import qualified Data.Text as T
----------------
--[ Commands ]--
----------------
data TestCommand = TestGHC TestOptions
---------------
--[ Options ]--
---------------
data TestOptions = TestOptions
{ testVer :: Maybe ToolVersion
, testBindist :: Maybe URI
, addMakeArgs :: [T.Text]
}
---------------
--[ Footers ]--
---------------
testFooter :: String
testFooter = [s|Discussion:
Runs test suites from the test bindist.|]
---------------
--[ Parsers ]--
---------------
testParser :: Parser TestCommand
testParser =
subparser
( command
"ghc"
( TestGHC
<$> info
(testOpts (Just GHC) <**> helper)
( progDesc "Test GHC"
<> footerDoc (Just $ text testGHCFooter)
)
)
)
where
testGHCFooter :: String
testGHCFooter = [s|Discussion:
Runs the GHC test suite from the test bindist.|]
testOpts :: Maybe Tool -> Parser TestOptions
testOpts tool =
(\(u, v) args -> TestOptions v u args)
<$> ( ( (,)
<$> optional
(option
(eitherReader uriParser)
(short 'u' <> long "url" <> metavar "BINDIST_URL" <> help
"Install the specified version from this bindist"
<> completer (toolDlCompleter (fromMaybe GHC tool))
)
)
<*> (Just <$> toolVersionTagArgument Nothing tool)
)
<|> pure (Nothing, Nothing)
)
<*> many (argument str (metavar "MAKE_ARGS" <> help "Additional arguments to 'make', prefix with '-- ' (longopts)"))
---------------------------
--[ Effect interpreters ]--
---------------------------
type TestGHCEffects = [ DigestError
, ContentLengthError
, GPGError
, DownloadFailed
, NoDownload
, ArchiveResult
, TarDirDoesNotExist
, UnknownArchive
, TestFailed
, NextVerNotFound
, TagNotFound
, NoToolVersionSet
]
runTestGHC :: AppState
-> Excepts TestGHCEffects (ResourceT (ReaderT AppState IO)) a
-> IO (VEither TestGHCEffects a)
runTestGHC appstate' =
flip runReaderT appstate'
. runResourceT
. runE
@TestGHCEffects
-------------------
--[ Entrypoints ]--
-------------------
test :: TestCommand -> Settings -> IO AppState -> (ReaderT LeanAppState IO () -> IO ()) -> IO ExitCode
test testCommand settings getAppState' runLogger = case testCommand of
(TestGHC iopts) -> go iopts
where
go :: TestOptions -> IO ExitCode
go TestOptions{..} = do
s'@AppState{ dirs = Dirs{ .. } } <- liftIO getAppState'
(case testBindist of
Nothing -> runTestGHC s' $ do
(v, vi) <- liftE $ fromVersion testVer GHC
liftE $ testGHCVer (_tvVersion v) addMakeArgs
pure vi
Just uri -> do
runTestGHC s'{ settings = settings {noVerify = True}} $ do
(v, vi) <- liftE $ fromVersion testVer GHC
liftE $ testGHCBindist (DownloadInfo uri (Just $ RegexDir ".*/.*") "" Nothing) (_tvVersion v) addMakeArgs
pure vi
)
>>= \case
VRight _ -> do
runLogger $ logInfo "GHC test successful"
pure ExitSuccess
VLeft e -> do
runLogger $ do
logError $ T.pack $ prettyHFError e
logError $ "Also check the logs in " <> T.pack (fromGHCupPath logsDir)
pure $ ExitFailure 3

View File

@@ -13,6 +13,9 @@ module Main where
#if defined(BRICK)
import BrickMain ( brickMain )
#endif
#if defined(ANSI)
import AnsiMain ( ansiMain )
#endif
import qualified GHCup.GHC as GHC
import qualified GHCup.HLS as HLS
@@ -234,6 +237,9 @@ Report bugs at <https://github.com/haskell/ghcup-hs/issues>|]
UnSet _ -> pure ()
#if defined(BRICK)
Interactive -> pure ()
#endif
#if defined(ANSI)
InteractiveAnsi -> pure ()
#endif
-- check for new tools
_
@@ -292,10 +298,14 @@ Report bugs at <https://github.com/haskell/ghcup-hs/issues>|]
Interactive -> do
s' <- appState
liftIO $ brickMain s' >> pure ExitSuccess
#endif
#if defined(ANSI)
InteractiveAnsi -> do
s' <- appState
liftIO $ ansiMain s' >> 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 runAppState runLeanAppState runLogger
UnSet unsetCommand -> unset unsetCommand runLeanAppState runLogger
List lo -> list lo no_color runAppState

View File

@@ -5,7 +5,8 @@ optional-packages: ./vendored/*/*.cabal
optimization: 2
package ghcup
flags: +tui
tests: True
flags: +tui-ansi
source-repository-package
type: git
@@ -14,7 +15,7 @@ source-repository-package
constraints: http-io-streams -brotli,
any.Cabal ==3.6.2.0,
any.aeson >= 2.0.1.0
any.aeson >= 2.0.1.0,
package libarchive
flags: -system-libarchive

View File

@@ -1,4 +1,4 @@
cabal-version: 2.4
cabal-version: 3.0
name: ghcup
version: 0.1.18.1
license: LGPL-3.0-only
@@ -41,6 +41,11 @@ flag tui
default: False
manual: True
flag tui-ansi
description: Build the ansi-terminal powered tui (ghcup tui-ansi).
default: False
manual: True
flag internal-downloader
description:
Compile the internal downloader, which links against OpenSSL. This is disabled on windows.
@@ -219,7 +224,6 @@ executable ghcup
GHCup.OptParse.Rm
GHCup.OptParse.Run
GHCup.OptParse.Set
GHCup.OptParse.Test
GHCup.OptParse.ToolRequirements
GHCup.OptParse.UnSet
GHCup.OptParse.Upgrade
@@ -280,6 +284,14 @@ executable ghcup
if flag(internal-downloader)
cpp-options: -DINTERNAL_DOWNLOADER
if flag(tui-ansi)
cpp-options: -DANSI
other-modules: AnsiMain
build-depends:
, ansi-terminal
, ansi-terminal-game
, transformers ^>=0.5
if (flag(tui) && !os(windows))
cpp-options: -DBRICK
other-modules: BrickMain

View File

@@ -83,10 +83,9 @@ allHFError = unlines allErrors
, let proxy = Proxy :: Proxy ToolShadowed in format proxy
, let proxy = Proxy :: Proxy ContentLengthError in format proxy
, ""
, "# high level errors (4000+)"
, "# high level errors (5000+)"
, let proxy = Proxy :: Proxy DownloadFailed in format proxy
, let proxy = Proxy :: Proxy InstallSetError in format proxy
, let proxy = Proxy :: Proxy TestFailed in format proxy
, let proxy = Proxy :: Proxy BuildFailed in format proxy
, let proxy = Proxy :: Proxy GHCupSetError in format proxy
, ""
@@ -162,6 +161,7 @@ prettyHFError e =
let errorCode = "GHCup-" <> padIntAndShow (eNum e)
in ("[" <> linkEscapeCode errorCode (hfErrorLink errorCode) <> "] ") <> prettyShow e
where
linkEscapeCode linkText link = "\ESC]8;;" <> link <> "\ESC\\" <> linkText <> "\ESC]8;;\ESC\\"
hfErrorLink errorCode = "https://errors.haskell.org/messages/" <> errorCode
padIntAndShow i
| i < 10 = "0000" <> show i
@@ -178,9 +178,6 @@ class HFErrorProject a where
eDesc :: Proxy a -> String
linkEscapeCode :: String -> String -> String
linkEscapeCode linkText link = "\ESC]8;;" <> link <> "\ESC\\" <> linkText <> "\ESC]8;;\ESC\\"
------------------------
--[ Low-level errors ]--
@@ -678,22 +675,6 @@ instance HFErrorProject InstallSetError where
eDesc _ = "Installation or setting the tool failed."
-- | 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)
instance Pretty TestFailed where
pPrint (TestFailed path reason) =
case reason of
VMaybe (_ :: TestFailed) -> pPrint reason
_ -> text ("The test failed. GHC test suite is fragile and non-portable. Please also check out the " <> linkEscapeCode "issue tracker" " https://gitlab.haskell.org/ghc/ghc/-/issues/?sort=updated_desc&state=opened&label_name%5B%5D=testsuite&label_name%5B%5D=packaging&first_page_size=20" <> ".\nBuild dir was:") <+> text path <+> text "\nReason was:" <+> pPrint reason
deriving instance Show TestFailed
instance HFErrorProject TestFailed where
eBase _ = 4000
eNum (TestFailed _ xs2) = 4000 + eNum xs2
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)

View File

@@ -86,144 +86,6 @@ data GHCVer v = SourceDist v
--------------------
--[ 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
)
=> Version
-> [T.Text]
-> Excepts
'[ DigestError
, ContentLengthError
, GPGError
, DownloadFailed
, NoDownload
, ArchiveResult
, TarDirDoesNotExist
, UnknownArchive
, TestFailed
]
m
()
testGHCVer ver addMakeArgs = do
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
dlInfo <-
preview (ix GHC % ix ver % viTestDL % _Just) dls
?? NoDownload
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
-> Version
-> [T.Text]
-> Excepts
'[ DigestError
, ContentLengthError
, GPGError
, DownloadFailed
, NoDownload
, ArchiveResult
, TarDirDoesNotExist
, UnknownArchive
, TestFailed
]
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
-> Version -- ^ 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)
-> Version -- ^ The GHC version
-> [T.Text] -- ^ additional configure args for bindist
-> Excepts '[ProcessError] m ()
testUnpackedGHC path ver addMakeArgs = do
lift $ logInfo $ "Testing GHC version " <> prettyVer ver <> "!"
ghcDir <- lift $ ghcupGHCDir (mkTVer ver)
let ghcBinDir = fromGHCupPath ghcDir </> "bin"
env <- liftIO $ addToPath ghcBinDir False
lEM $ make' (fmap T.unpack addMakeArgs)
(Just $ fromGHCupPath path)
"ghc-test"
(Just $ ("STAGE1_GHC", "ghc-" <> T.unpack (prettyVer ver)) : env)
pure ()
---------------------
--[ Tool fetching ]--
---------------------

View File

@@ -138,7 +138,6 @@ data VersionInfo = VersionInfo
{ _viTags :: [Tag] -- ^ version specific tag
, _viChangeLog :: Maybe URI
, _viSourceDL :: Maybe DownloadInfo -- ^ source tarball
, _viTestDL :: Maybe DownloadInfo -- ^ test tarball
, _viArch :: ArchitectureSpec -- ^ descend for binary downloads per arch
-- informative messages
, _viPostInstall :: Maybe Text

View File

@@ -93,7 +93,6 @@ import qualified Data.List.NonEmpty as NE
import qualified Streamly.Prelude as S
import Control.DeepSeq (force)
import GHC.IO (evaluate)
import System.Environment (getEnvironment, setEnv)
-- $setup
@@ -968,28 +967,11 @@ make :: ( MonadThrow m
=> [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
make args workdir = 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
execLogged mymake args workdir "ghc-make" Nothing
makeOut :: (MonadReader env m, HasDirs env, MonadIO m)
=> [String]
@@ -1300,22 +1282,6 @@ warnAboutHlsCompatibility = do
addToPath :: FilePath
-> Bool -- ^ if False will prepend
-> IO [(String, String)]
addToPath path append = do
cEnv <- Map.fromList <$> getEnvironment
let paths = ["PATH", "Path"]
curPaths = (\x -> maybe [] splitSearchPath (Map.lookup x cEnv)) =<< paths
{- HLINT ignore "Redundant bracket" -}
newPath = intercalate [searchPathSeparator] (if append then (curPaths ++ [path]) else (path : curPaths))
envWithoutPath = foldr (\x y -> Map.delete x y) cEnv paths
pathVar = if isWindows then "Path" else "PATH"
envWithNewPath = Map.toList $ Map.insert pathVar newPath envWithoutPath
liftIO $ setEnv pathVar newPath
return envWithNewPath
-----------
--[ Git ]--
-----------

View File

@@ -6,6 +6,7 @@ packages:
extra-deps:
- Cabal-3.6.2.0@sha256:e2266e14758c1f799220fad7f0d4b0b4ec567d81b7ba3faea17ff76d4c31de95,12437
- IfElse-0.85@sha256:6939b94acc6a55f545f63a168a349dd2fbe4b9a7cca73bf60282db5cc6aa47d2,445
- ansi-terminal-game-1.8.0.0@sha256:001cf786098d9f1056ac6055ff3f598054b5c231b7343e76abb686d4f485855d,6977
- ascii-string-1.0.1.4@sha256:fa34f1d9ba57e8e89c0d4c9cef5e01ba32cb2d4373d13f92dcc0b531a6c6749b,2582
- base16-bytestring-0.1.1.7@sha256:0021256a9628971c08da95cb8f4d0d72192f3bb8a7b30b55c080562d17c43dd3,2231
- brick-0.64@sha256:f03fa14607c22cf48af99e24c44f79a0fb073f7ec229f15e969fed9ff73c93f6,16530
@@ -27,6 +28,7 @@ extra-deps:
- http-io-streams-0.1.6.0@sha256:53f5bab177efb52cd65ec396fd04ed59b93e5f919fb3700cd7dacd6cfce6f06d,3582
- libarchive-3.0.3.0
- libyaml-streamly-0.2.1
- linebreak-1.1.0.1@sha256:b253873c3f98189eb22a5a9f0405677cde125c09666b63c3117f497c01c95893,1397
- lzma-static-5.2.5.3@sha256:2758ee58c35992fcf7db78e98684c357a16a82fa2a4e7c352a6c210c08c555d8,7308
- optics-0.4@sha256:9fb69bf0195b8d8f1f8cd0098000946868b8a3c3ffb51e5b64f79fc600c3eb4c,6568
- optics-core-0.4@sha256:59e04aebca536bd011ae50c781937f45af4c1456af1eb9fb578f9a69eee293cd,4995
@@ -36,8 +38,10 @@ extra-deps:
- primitive-0.7.1.0@sha256:29de6bfd0cf8ba023ceb806203dfbec0e51e3524e75ffe41056f70b4229c6f0f,2728
- regex-posix-clib-2.7
- streamly-0.8.2@sha256:ec521b7c1c4db068501c35804af77f40b7d34232f5e29d9b99e722229040eb80,23500
- unicode-data-0.3.0@sha256:0545e079705a5381d0893f8fe8daaa08fc9174baeab269b9cf651817d8eadbc6,5123
- strict-base-0.4.0.0@sha256:2ff4e43cb95eedf2995558d7fc34d19362846413dd39e6aa6a5b3ea8228fef9f,1248
- timers-tick-0.5.0.1@sha256:91d4b03266715c6969b82cb24e57a6b47191a4d2f95e9a92e0ad3f7301cc7c8b,1552
- unicode-data-0.3.0@sha256:0545e079705a5381d0893f8fe8daaa08fc9174baeab269b9cf651817d8eadbc6,5123
- unidecode-0.1.0.4@sha256:99581ee1ea334a4596a09ae3642e007808457c66893b587e965b31f15cbf8c4d,1144
- xor-0.0.1.0@sha256:f8362b4a68562b9afbcd727ff64c1a303970df3a032e0033d2f4c094c3501df3,2243
- yaml-streamly-0.12.1
@@ -60,6 +64,9 @@ flags:
streamly:
use-unliftio: true
ghcup:
tui-ansi: true
ghc-options:
"$locals": -O2
streamly: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16

View File

@@ -285,8 +285,7 @@
"base-8.7.6",
"Latest",
"Prerelease"
],
"viTestDL": null
]
},
"7.5.5": {
"viArch": {
@@ -388,8 +387,7 @@
"base-4.7.6",
"\u0001+n𫛚\r",
"Latest"
],
"viTestDL": null
]
},
"7.7.6": {
"viArch": {
@@ -511,8 +509,7 @@
"old",
"base-3.1.4",
"Prerelease"
],
"viTestDL": null
]
},
"8.8.6": {
"viArch": {
@@ -827,8 +824,7 @@
"base-5.2.3",
"Prerelease",
"Latest"
],
"viTestDL": null
]
}
},
"HLS": {
@@ -1088,8 +1084,7 @@
"Latest",
"Latest",
"Recommended"
],
"viTestDL": null
]
},
"2.1.4": {
"viArch": {
@@ -1245,8 +1240,7 @@
"viTags": [
"Prerelease",
"base-4.7.4"
],
"viTestDL": null
]
},
"3.3.7": {
"viArch": {
@@ -1676,8 +1670,7 @@
},
"dlUri": "https:mkzzunx"
},
"viTags": [],
"viTestDL": null
"viTags": []
},
"3.5.3": {
"viArch": {
@@ -1979,8 +1972,7 @@
"old",
"Recommended",
"old"
],
"viTestDL": null
]
},
"5.2.3": {
"viArch": {
@@ -2317,8 +2309,7 @@
"Latest",
"Recommended",
"Recommended"
],
"viTestDL": null
]
},
"8.5.2": {
"viArch": {
@@ -2440,8 +2431,7 @@
"Latest",
"Latest",
"base-8.7.3"
],
"viTestDL": null
]
}
}
},
@@ -2890,8 +2880,7 @@
},
"dlUri": "https:zxekodom"
},
"viTags": [],
"viTestDL": null
"viTags": []
},
"3.2.1": {
"viArch": {
@@ -3111,8 +3100,7 @@
"base-7.7.6",
"𩺈𥲬􅚷\u0015A~",
"old"
],
"viTestDL": null
]
},
"4.5.3": {
"viArch": {
@@ -3342,8 +3330,7 @@
"base-1.5.2",
"Latest",
"old"
],
"viTestDL": null
]
},
"7.3.9": {
"viArch": {
@@ -3701,8 +3688,7 @@
"base-1.6.1",
"Prerelease",
"old"
],
"viTestDL": null
]
}
},
"GHCup": {
@@ -3761,8 +3747,7 @@
"Latest",
"\u0005s톕$󵰇\"g",
"Prerelease"
],
"viTestDL": null
]
},
"3.5.3": {
"viArch": {
@@ -3895,8 +3880,7 @@
"Latest",
"xZ\u000b",
"Recommended"
],
"viTestDL": null
]
},
"3.8.5": {
"viArch": {
@@ -4009,8 +3993,7 @@
"viSourceDL": null,
"viTags": [
"old"
],
"viTestDL": null
]
},
"4.1.6": {
"viArch": {
@@ -4196,8 +4179,7 @@
"viTags": [
"Latest",
"old"
],
"viTestDL": null
]
},
"7.5.4": {
"viArch": {
@@ -4474,8 +4456,7 @@
"viSourceDL": null,
"viTags": [
"鲤"
],
"viTestDL": null
]
}
},
"HLS": {
@@ -4846,8 +4827,7 @@
"",
"Ctj",
"􃰍|W󶶟d`"
],
"viTestDL": null
]
},
"3.5.1": {
"viArch": {
@@ -4957,8 +4937,7 @@
"old",
"Latest",
"Recommended"
],
"viTestDL": null
]
},
"4.2.2": {
"viArch": {
@@ -5051,8 +5030,7 @@
"Recommended",
"Recommended",
"Latest"
],
"viTestDL": null
]
},
"4.4.1": {
"viArch": {
@@ -5144,8 +5122,7 @@
"Latest",
"Latest",
"Recommended"
],
"viTestDL": null
]
},
"5.7.2": {
"viArch": {
@@ -5496,8 +5473,7 @@
"Prerelease",
"Prerelease",
"Recommended"
],
"viTestDL": null
]
},
"7.1.4": {
"viArch": {
@@ -5583,8 +5559,7 @@
"Latest",
"\u0013ADq\u001bX<",
"base-8.2.4"
],
"viTestDL": null
]
},
"8.2.3": {
"viArch": {
@@ -5692,8 +5667,7 @@
"𠖛",
"恦AD假n#",
"Prerelease"
],
"viTestDL": null
]
},
"8.3.5": {
"viArch": {
@@ -6096,8 +6070,7 @@
"Prerelease",
"%󵠣R灡𑈃pS",
"Latest"
],
"viTestDL": null
]
}
}
},
@@ -7382,8 +7355,7 @@
"old",
"Latest",
"base-8.5.8"
],
"viTestDL": null
]
},
"2.1.4": {
"viArch": {
@@ -8071,8 +8043,7 @@
"",
"\u0018\u0017GF󾐘\u0018",
"base-8.7.8"
],
"viTestDL": null
]
},
"4.6.8": {
"viArch": {
@@ -8358,8 +8329,7 @@
"base-8.1.6",
"old",
"Latest"
],
"viTestDL": null
]
},
"5.1.8": {
"viArch": {
@@ -8559,8 +8529,7 @@
"Prerelease",
"~X6*𦥹",
"base-2.1.6"
],
"viTestDL": null
]
},
"5.4.7": {
"viArch": {},
@@ -8580,8 +8549,7 @@
"󱪀9pR𥎷H",
"base-7.5.6",
"Recommended"
],
"viTestDL": null
]
}
},
"Stack": {
@@ -8923,8 +8891,7 @@
},
"dlUri": "http:gji"
},
"viTags": [],
"viTestDL": null
"viTags": []
},
"7.2.3": {
"viArch": {
@@ -9069,8 +9036,7 @@
"old",
"Recommended",
"base-2.5.2"
],
"viTestDL": null
]
}
}
},
@@ -10447,8 +10413,7 @@
"Recommended",
"S鴖xz󾤞",
"Prerelease"
],
"viTestDL": null
]
},
"4.4.4": {
"viArch": {
@@ -10760,8 +10725,7 @@
"Prerelease",
"old",
"Latest"
],
"viTestDL": null
]
},
"5.5.4": {
"viArch": {
@@ -11141,8 +11105,7 @@
"Latest",
"base-1.8.1",
"Recommended"
],
"viTestDL": null
]
},
"5.6.4": {
"viArch": {
@@ -11385,8 +11348,7 @@
"Prerelease",
">/~l\u0019\u0001F\u0003",
"base-4.4.6"
],
"viTestDL": null
]
},
"6.7.3": {
"viArch": {},
@@ -11405,8 +11367,7 @@
"viTags": [
"old",
"old"
],
"viTestDL": null
]
},
"8.5.5": {
"viArch": {},
@@ -11427,8 +11388,7 @@
"Latest",
"base-3.6.3",
"Recommended"
],
"viTestDL": null
]
},
"8.6.5": {
"viArch": {
@@ -11810,8 +11770,7 @@
"v斾)k",
"Prerelease",
"Latest"
],
"viTestDL": null
]
}
},
"GHC": {},
@@ -13582,8 +13541,7 @@
},
"viTags": [
"Prerelease"
],
"viTestDL": null
]
},
"2.6.7": {
"viArch": {
@@ -13627,8 +13585,7 @@
"viSourceDL": null,
"viTags": [
"Latest"
],
"viTestDL": null
]
},
"3.3.5": {
"viArch": {
@@ -13651,8 +13608,7 @@
"&Z3𭹡X",
"Prerelease",
"Prerelease"
],
"viTestDL": null
]
},
"3.4.4": {
"viArch": {
@@ -14109,8 +14065,7 @@
"f8\u0017xNft(",
"Recommended",
"Prerelease"
],
"viTestDL": null
]
},
"6.5.7": {
"viArch": {
@@ -14287,8 +14242,7 @@
"dlSubdir": "􂮄qG+0󰊒t",
"dlUri": "http:vvn"
},
"viTags": [],
"viTestDL": null
"viTags": []
},
"6.6.3": {
"viArch": {
@@ -14356,8 +14310,7 @@
"",
"\u0014𣉈C\u0018󼀇V",
"Recommended"
],
"viTestDL": null
]
},
"8.5.4": {
"viArch": {
@@ -14510,8 +14463,7 @@
"Latest",
"\u0005I{5\u0013",
"base-3.8.8"
],
"viTestDL": null
]
}
},
"GHCup": {
@@ -14683,8 +14635,7 @@
"Latest",
"old",
"Latest"
],
"viTestDL": null
]
},
"4.3.4": {
"viArch": {
@@ -14880,8 +14831,7 @@
"\u0017M􆼘󴞻",
"old",
"Recommended"
],
"viTestDL": null
]
},
"8.6.2": {
"viArch": {
@@ -15217,8 +15167,7 @@
"Prerelease",
"Prerelease",
"base-5.1.6"
],
"viTestDL": null
]
}
},
"Stack": {
@@ -15575,8 +15524,7 @@
},
"viTags": [
"Latest"
],
"viTestDL": null
]
}
}
},

File diff suppressed because it is too large Load Diff