Support stacks installation strategy and metadata wrt #892

This commit is contained in:
2023-10-22 21:50:27 +08:00
parent d14526059b
commit 5f73320b29
24 changed files with 843 additions and 183 deletions

View File

@@ -23,6 +23,7 @@ module GHCup.Types.JSON where
import GHCup.Types
import GHCup.Types.JSON.Utils
import GHCup.Types.JSON.Versions ()
import GHCup.Prelude.MegaParsec
import Control.Applicative ( (<|>) )
@@ -112,34 +113,6 @@ instance FromJSONKey GHCTargetVersion where
Right x -> pure x
Left e -> fail $ "Failure in GHCTargetVersion (FromJSONKey)" <> show e
instance ToJSON Versioning where
toJSON = toJSON . prettyV
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
instance ToJSONKey Versioning where
toJSONKey = toJSONKeyText $ \x -> prettyV x
instance FromJSONKey Versioning where
fromJSONKey = FromJSONKeyTextParser $ \t -> case versioning t of
Right x -> pure x
Left e -> fail $ "Failure in Versioning (FromJSONKey)" <> show e
instance ToJSONKey (Maybe Versioning) where
toJSONKey = toJSONKeyText $ \case
Just x -> prettyV x
Nothing -> T.pack "unknown_versioning"
instance FromJSONKey (Maybe Versioning) where
fromJSONKey = FromJSONKeyTextParser $ \t ->
if t == T.pack "unknown_versioning" then pure Nothing else just t
where
just t = case versioning t of
Right x -> pure $ Just x
Left e -> fail $ "Failure in (Maybe Versioning) (FromJSONKey)" <> show e
instance ToJSONKey Platform where
toJSONKey = toJSONKeyText $ \case
@@ -176,43 +149,6 @@ instance ToJSONKey Architecture where
instance FromJSONKey Architecture where
fromJSONKey = genericFromJSONKey defaultJSONKeyOptions
instance ToJSONKey (Maybe Version) where
toJSONKey = toJSONKeyText $ \case
Just x -> prettyVer x
Nothing -> T.pack "unknown_version"
instance FromJSONKey (Maybe Version) where
fromJSONKey = FromJSONKeyTextParser $ \t ->
if t == T.pack "unknown_version" then pure Nothing else just t
where
just t = case version t of
Right x -> pure $ Just x
Left e -> fail $ "Failure in (Maybe Version) (FromJSONKey)" <> show e
instance ToJSON Version where
toJSON = toJSON . prettyVer
instance FromJSON Version where
parseJSON = withText "Version" $ \t -> case version t of
Right x -> pure x
Left e -> fail $ "Failure in Version (FromJSON)" <> show e
instance ToJSONKey Version where
toJSONKey = toJSONKeyText $ \x -> prettyVer x
instance FromJSONKey Version where
fromJSONKey = FromJSONKeyTextParser $ \t -> case version t of
Right x -> pure x
Left e -> fail $ "Failure in Version (FromJSONKey)" <> show e
instance ToJSON PVP where
toJSON = toJSON . prettyPVP
instance FromJSON PVP where
parseJSON = withText "PVP" $ \t -> case pvp t of
Right x -> pure x
Left e -> fail $ "Failure in PVP (FromJSON)" <> show e
instance ToJSONKey Tool where
toJSONKey = genericToJSONKey defaultJSONKeyOptions
@@ -348,6 +284,7 @@ deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Downlo
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''VersionInfo
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''GHCupInfo
deriveToJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''URLSource
deriveJSON defaultOptions { sumEncoding = ObjectWithSingleField, constructorTagModifier = \str' -> if str' == "StackSetupURL" then str' else maybe str' T.unpack . T.stripPrefix (T.pack "S") . T.pack $ str' } ''StackSetupURLSource
deriveJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''Key
deriveJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' T.unpack . T.stripPrefix (T.pack "k-") . T.pack . kebab $ str' } ''UserKeyBindings
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel, unwrapUnaryRecords = True } ''Port

View File

@@ -0,0 +1,90 @@
{-# OPTIONS_GHC -Wno-orphans #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-|
Module : GHCup.Types.JSON.Versions
Description : GHCup Version JSON types/instances
Copyright : (c) Julian Ospald, 2020
License : LGPL-3.0
Maintainer : hasufell@hasufell.de
Stability : experimental
Portability : portable
-}
module GHCup.Types.JSON.Versions where
import Data.Aeson hiding (Key)
import Data.Aeson.Types hiding (Key)
import Data.Versions
import qualified Data.Text as T
instance ToJSON Versioning where
toJSON = toJSON . prettyV
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
instance ToJSONKey Versioning where
toJSONKey = toJSONKeyText $ \x -> prettyV x
instance FromJSONKey Versioning where
fromJSONKey = FromJSONKeyTextParser $ \t -> case versioning t of
Right x -> pure x
Left e -> fail $ "Failure in Versioning (FromJSONKey)" <> show e
instance ToJSONKey (Maybe Versioning) where
toJSONKey = toJSONKeyText $ \case
Just x -> prettyV x
Nothing -> T.pack "unknown_versioning"
instance FromJSONKey (Maybe Versioning) where
fromJSONKey = FromJSONKeyTextParser $ \t ->
if t == T.pack "unknown_versioning" then pure Nothing else just t
where
just t = case versioning t of
Right x -> pure $ Just x
Left e -> fail $ "Failure in (Maybe Versioning) (FromJSONKey)" <> show e
instance ToJSONKey (Maybe Version) where
toJSONKey = toJSONKeyText $ \case
Just x -> prettyVer x
Nothing -> T.pack "unknown_version"
instance FromJSONKey (Maybe Version) where
fromJSONKey = FromJSONKeyTextParser $ \t ->
if t == T.pack "unknown_version" then pure Nothing else just t
where
just t = case version t of
Right x -> pure $ Just x
Left e -> fail $ "Failure in (Maybe Version) (FromJSONKey)" <> show e
instance ToJSON Version where
toJSON = toJSON . prettyVer
instance FromJSON Version where
parseJSON = withText "Version" $ \t -> case version t of
Right x -> pure x
Left e -> fail $ "Failure in Version (FromJSON)" <> show e
instance ToJSONKey Version where
toJSONKey = toJSONKeyText $ \x -> prettyVer x
instance FromJSONKey Version where
fromJSONKey = FromJSONKeyTextParser $ \t -> case version t of
Right x -> pure x
Left e -> fail $ "Failure in Version (FromJSONKey)" <> show e
instance ToJSON PVP where
toJSON = toJSON . prettyPVP
instance FromJSON PVP where
parseJSON = withText "PVP" $ \t -> case pvp t of
Right x -> pure x
Left e -> fail $ "Failure in PVP (FromJSON)" <> show e

180
lib/GHCup/Types/Stack.hs Normal file
View File

@@ -0,0 +1,180 @@
{-# OPTIONS_GHC -Wno-orphans #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE FlexibleInstances #-}
{-|
Module : GHCup.Types.Stack
Description : GHCup types.Stack
Copyright : (c) Julian Ospald, 2023
License : LGPL-3.0
Maintainer : hasufell@hasufell.de
Stability : experimental
Portability : portable
-}
module GHCup.Types.Stack where
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 qualified Data.Map as Map
import qualified GHC.Generics as GHC
--------------------------------------
--[ Stack download info copy pasta ]--
--------------------------------------
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)
}
deriving (Show, Eq, GHC.Generic)
instance NFData SetupInfo
instance FromJSON SetupInfo where
parseJSON = withObject "SetupInfo" $ \o -> do
siSevenzExe <- o .:? "sevenzexe-info"
siSevenzDll <- o .:? "sevenzdll-info"
siMsys2 <- o .:? "msys2" .!= mempty
siGHCs <- o .:? "ghc" .!= mempty
siStack <- o .:? "stack" .!= mempty
pure SetupInfo {..}
instance ToJSON SetupInfo where
toJSON (SetupInfo {..}) = object [ "sevenzexe-info" .= siSevenzExe
, "sevenzdll-info" .= siSevenzDll
, "msys2" .= siMsys2
, "ghc" .= siGHCs
, "stack" .= siStack
]
-- | For the @siGHCs@ field maps are deeply merged. For all fields the values
-- from the first @SetupInfo@ win.
instance Semigroup SetupInfo where
l <> r =
SetupInfo
{ siSevenzExe = siSevenzExe l <|> siSevenzExe r
, siSevenzDll = siSevenzDll l <|> siSevenzDll r
, siMsys2 = siMsys2 l <> siMsys2 r
, siGHCs = Map.unionWith (<>) (siGHCs l) (siGHCs r)
, siStack = Map.unionWith (<>) (siStack l) (siStack r) }
instance Monoid SetupInfo where
mempty =
SetupInfo
{ siSevenzExe = Nothing
, siSevenzDll = Nothing
, siMsys2 = Map.empty
, siGHCs = Map.empty
, siStack = Map.empty
}
mappend = (<>)
-- | Build of the compiler distribution (e.g. standard, gmp4, tinfo6)
-- | Information for a file to download.
data DownloadInfo = DownloadInfo
{ downloadInfoUrl :: Text
-- ^ URL or absolute file path
, downloadInfoContentLength :: Maybe Int
, downloadInfoSha1 :: Maybe ByteString
, downloadInfoSha256 :: Maybe ByteString
}
deriving (Show, Eq, GHC.Generic)
instance ToJSON DownloadInfo where
toJSON (DownloadInfo {..}) = object [ "url" .= downloadInfoUrl
, "content-length" .= downloadInfoContentLength
, "sha1" .= (decodeUtf8 <$> downloadInfoSha1)
, "sha256" .= (decodeUtf8 <$> downloadInfoSha256)
]
instance NFData DownloadInfo
instance FromJSON DownloadInfo where
parseJSON = withObject "DownloadInfo" parseDownloadInfoFromObject
-- | Parse JSON in existing object for 'DownloadInfo'
parseDownloadInfoFromObject :: Object -> Parser DownloadInfo
parseDownloadInfoFromObject o = do
url <- o .: "url"
contentLength <- o .:? "content-length"
sha1TextMay <- o .:? "sha1"
sha256TextMay <- o .:? "sha256"
pure
DownloadInfo
{ downloadInfoUrl = url
, downloadInfoContentLength = contentLength
, downloadInfoSha1 = fmap encodeUtf8 sha1TextMay
, downloadInfoSha256 = fmap encodeUtf8 sha256TextMay
}
data VersionedDownloadInfo = VersionedDownloadInfo
{ vdiVersion :: Version
, vdiDownloadInfo :: DownloadInfo
}
deriving (Show, Eq, GHC.Generic)
instance ToJSON VersionedDownloadInfo where
toJSON (VersionedDownloadInfo {vdiDownloadInfo = DownloadInfo{..}, ..})
= object [ "version" .= vdiVersion
, "url" .= downloadInfoUrl
, "content-length" .= downloadInfoContentLength
, "sha1" .= (decodeUtf8 <$> downloadInfoSha1)
, "sha256" .= (decodeUtf8 <$> downloadInfoSha256)
]
instance NFData VersionedDownloadInfo
instance FromJSON VersionedDownloadInfo where
parseJSON = withObject "VersionedDownloadInfo" $ \o -> do
ver' <- o .: "version"
downloadInfo <- parseDownloadInfoFromObject o
pure VersionedDownloadInfo
{ vdiVersion = ver'
, vdiDownloadInfo = downloadInfo
}
data GHCDownloadInfo = GHCDownloadInfo
{ gdiConfigureOpts :: [Text]
, gdiConfigureEnv :: Map Text Text
, gdiDownloadInfo :: DownloadInfo
}
deriving (Show, Eq, GHC.Generic)
instance NFData GHCDownloadInfo
instance ToJSON GHCDownloadInfo where
toJSON (GHCDownloadInfo {gdiDownloadInfo = DownloadInfo {..}, ..})
= object [ "configure-opts" .= gdiConfigureOpts
, "configure-env" .= gdiConfigureEnv
, "url" .= downloadInfoUrl
, "content-length" .= downloadInfoContentLength
, "sha1" .= (decodeUtf8 <$> downloadInfoSha1)
, "sha256" .= (decodeUtf8 <$> downloadInfoSha256)
]
instance FromJSON GHCDownloadInfo where
parseJSON = withObject "GHCDownloadInfo" $ \o -> do
configureOpts <- o .:? "configure-opts" .!= mempty
configureEnv <- o .:? "configure-env" .!= mempty
downloadInfo <- parseDownloadInfoFromObject o
pure GHCDownloadInfo
{ gdiConfigureOpts = configureOpts
, gdiConfigureEnv = configureEnv
, gdiDownloadInfo = downloadInfo
}