2020-01-11 20:15:05 +00:00
|
|
|
{-# OPTIONS_GHC -Wno-orphans #-}
|
|
|
|
|
|
|
|
{-# LANGUAGE DataKinds #-}
|
|
|
|
{-# LANGUAGE DeriveGeneric #-}
|
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
|
|
|
{-# LANGUAGE FlexibleInstances #-}
|
|
|
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
2020-03-21 21:19:37 +00:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2020-01-11 20:15:05 +00:00
|
|
|
{-# LANGUAGE QuasiQuotes #-}
|
|
|
|
{-# LANGUAGE TemplateHaskell #-}
|
|
|
|
{-# LANGUAGE TypeFamilies #-}
|
|
|
|
|
2020-07-21 23:08:58 +00:00
|
|
|
{-|
|
|
|
|
Module : GHCup.Types.JSON
|
|
|
|
Description : GHCup JSON types/instances
|
|
|
|
Copyright : (c) Julian Ospald, 2020
|
2020-07-30 18:04:02 +00:00
|
|
|
License : LGPL-3.0
|
2020-07-21 23:08:58 +00:00
|
|
|
Maintainer : hasufell@hasufell.de
|
|
|
|
Stability : experimental
|
2021-05-14 21:09:45 +00:00
|
|
|
Portability : portable
|
2020-07-21 23:08:58 +00:00
|
|
|
-}
|
2020-01-11 20:15:05 +00:00
|
|
|
module GHCup.Types.JSON where
|
|
|
|
|
|
|
|
import GHCup.Types
|
2023-10-24 16:35:41 +00:00
|
|
|
import GHCup.Types.Stack (SetupInfo)
|
2022-02-05 23:32:18 +00:00
|
|
|
import GHCup.Types.JSON.Utils
|
2023-10-22 13:50:27 +00:00
|
|
|
import GHCup.Types.JSON.Versions ()
|
2022-05-21 20:54:18 +00:00
|
|
|
import GHCup.Prelude.MegaParsec
|
2020-01-11 20:15:05 +00:00
|
|
|
|
2020-08-10 20:22:48 +00:00
|
|
|
import Control.Applicative ( (<|>) )
|
2021-10-13 17:47:14 +00:00
|
|
|
import Data.Aeson hiding (Key)
|
2020-01-11 20:15:05 +00:00
|
|
|
import Data.Aeson.TH
|
2021-10-13 17:47:14 +00:00
|
|
|
import Data.Aeson.Types hiding (Key)
|
2022-12-03 16:15:13 +00:00
|
|
|
import Data.ByteString ( ByteString )
|
2020-11-20 17:37:48 +00:00
|
|
|
import Data.List.NonEmpty ( NonEmpty(..) )
|
2023-10-24 16:35:41 +00:00
|
|
|
import Data.Maybe
|
2020-01-11 20:15:05 +00:00
|
|
|
import Data.Text.Encoding as E
|
2023-10-24 16:35:41 +00:00
|
|
|
import Data.Foldable
|
2020-01-11 20:15:05 +00:00
|
|
|
import Data.Versions
|
2020-11-20 17:37:48 +00:00
|
|
|
import Data.Void
|
2020-01-11 20:15:05 +00:00
|
|
|
import URI.ByteString
|
2020-10-24 20:03:00 +00:00
|
|
|
import Text.Casing
|
2020-01-11 20:15:05 +00:00
|
|
|
|
2020-11-20 17:37:48 +00:00
|
|
|
import qualified Data.List.NonEmpty as NE
|
2020-01-11 20:15:05 +00:00
|
|
|
import qualified Data.Text as T
|
2022-02-05 23:32:18 +00:00
|
|
|
import qualified Data.Text.Encoding.Error as E
|
2020-11-20 17:37:48 +00:00
|
|
|
import qualified Text.Megaparsec as MP
|
|
|
|
import qualified Text.Megaparsec.Char as MPC
|
2020-01-11 20:15:05 +00:00
|
|
|
|
|
|
|
|
2023-01-01 11:04:00 +00:00
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''MetaMode
|
2021-08-29 12:50:49 +00:00
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Architecture
|
2020-01-11 20:15:05 +00:00
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''LinuxDistro
|
2021-05-14 21:09:45 +00:00
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''VSep
|
2020-10-24 20:55:35 +00:00
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''MChunk
|
2020-01-11 20:15:05 +00:00
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Platform
|
2021-05-14 21:09:45 +00:00
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Mess
|
2023-10-13 08:09:35 +00:00
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Chunk
|
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Release
|
2020-01-11 20:15:05 +00:00
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''SemVer
|
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Tool
|
2020-10-24 20:03:00 +00:00
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''KeepDirs
|
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Downloader
|
2021-09-18 17:45:32 +00:00
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''GPGSetting
|
2022-11-12 06:12:13 +00:00
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' T.unpack . T.stripPrefix (T.pack "r-") . T.pack . kebab . tail $ str' } ''PlatformRequest
|
2020-01-11 20:15:05 +00:00
|
|
|
|
2020-04-22 00:33:35 +00:00
|
|
|
instance ToJSON Tag where
|
2020-04-25 10:06:41 +00:00
|
|
|
toJSON Latest = String "Latest"
|
|
|
|
toJSON Recommended = String "Recommended"
|
2020-07-28 18:55:00 +00:00
|
|
|
toJSON Prerelease = String "Prerelease"
|
2023-05-01 09:46:27 +00:00
|
|
|
toJSON Nightly = String "Nightly"
|
2020-10-09 20:55:33 +00:00
|
|
|
toJSON Old = String "old"
|
2020-04-25 10:06:41 +00:00
|
|
|
toJSON (Base pvp'') = String ("base-" <> prettyPVP pvp'')
|
2023-02-21 14:22:11 +00:00
|
|
|
toJSON LatestPrerelease = String "LatestPrerelease"
|
2023-05-01 09:46:27 +00:00
|
|
|
toJSON LatestNightly = String "LatestNightly"
|
2020-04-25 10:06:41 +00:00
|
|
|
toJSON (UnknownTag x ) = String (T.pack x)
|
2020-04-22 00:33:35 +00:00
|
|
|
|
|
|
|
instance FromJSON Tag where
|
|
|
|
parseJSON = withText "Tag" $ \t -> case T.unpack t of
|
2020-04-25 10:06:41 +00:00
|
|
|
"Latest" -> pure Latest
|
|
|
|
"Recommended" -> pure Recommended
|
2020-07-28 18:55:00 +00:00
|
|
|
"Prerelease" -> pure Prerelease
|
2023-05-01 09:46:27 +00:00
|
|
|
"Nightly" -> pure Nightly
|
2023-02-21 14:22:11 +00:00
|
|
|
"LatestPrerelease" -> pure LatestPrerelease
|
2023-05-01 09:46:27 +00:00
|
|
|
"LatestNightly" -> pure LatestNightly
|
2020-10-09 20:55:33 +00:00
|
|
|
"old" -> pure Old
|
2020-04-25 10:06:41 +00:00
|
|
|
('b' : 'a' : 's' : 'e' : '-' : ver') -> case pvp (T.pack ver') of
|
|
|
|
Right x -> pure $ Base x
|
|
|
|
Left e -> fail . show $ e
|
2020-04-22 00:33:35 +00:00
|
|
|
x -> pure (UnknownTag x)
|
2020-01-11 20:15:05 +00:00
|
|
|
|
|
|
|
instance ToJSON URI where
|
2022-02-05 23:32:18 +00:00
|
|
|
toJSON = toJSON . E.decodeUtf8With E.lenientDecode . serializeURIRef'
|
2020-01-11 20:15:05 +00:00
|
|
|
|
2022-03-10 19:26:51 +00:00
|
|
|
|
2020-01-11 20:15:05 +00:00
|
|
|
instance FromJSON URI where
|
|
|
|
parseJSON = withText "URL" $ \t ->
|
|
|
|
case parseURI strictURIParserOptions (encodeUtf8 t) of
|
|
|
|
Right x -> pure x
|
|
|
|
Left e -> fail . show $ e
|
|
|
|
|
2023-07-07 08:41:58 +00:00
|
|
|
instance ToJSON GHCTargetVersion 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 ToJSONKey GHCTargetVersion where
|
|
|
|
toJSONKey = toJSONKeyText $ \x -> tVerToText x
|
|
|
|
|
|
|
|
instance FromJSONKey GHCTargetVersion where
|
|
|
|
fromJSONKey = FromJSONKeyTextParser $ \t -> case MP.parse ghcTargetVerP "" t of
|
|
|
|
Right x -> pure x
|
|
|
|
Left e -> fail $ "Failure in GHCTargetVersion (FromJSONKey)" <> show e
|
|
|
|
|
2020-01-11 20:15:05 +00:00
|
|
|
|
|
|
|
instance ToJSONKey Platform where
|
|
|
|
toJSONKey = toJSONKeyText $ \case
|
|
|
|
Darwin -> T.pack "Darwin"
|
|
|
|
FreeBSD -> T.pack "FreeBSD"
|
|
|
|
Linux d -> T.pack ("Linux_" <> show d)
|
2021-05-14 21:09:45 +00:00
|
|
|
Windows -> T.pack "Windows"
|
2020-01-11 20:15:05 +00:00
|
|
|
|
|
|
|
instance FromJSONKey Platform where
|
|
|
|
fromJSONKey = FromJSONKeyTextParser $ \t -> if
|
|
|
|
| T.pack "Darwin" == t -> pure Darwin
|
|
|
|
| T.pack "FreeBSD" == t -> pure FreeBSD
|
2021-05-14 21:09:45 +00:00
|
|
|
| T.pack "Windows" == t -> pure Windows
|
2020-01-11 20:15:05 +00:00
|
|
|
| T.pack "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 -> pure $ Linux d
|
|
|
|
Nothing ->
|
|
|
|
fail
|
|
|
|
$ "Unexpected failure in decoding LinuxDistro: "
|
|
|
|
<> show dstr
|
|
|
|
Nothing -> fail "Unexpected failure in Platform stripPrefix"
|
2021-03-11 16:03:51 +00:00
|
|
|
| otherwise -> fail "Failure in Platform (FromJSONKey)"
|
2020-01-11 20:15:05 +00:00
|
|
|
|
|
|
|
instance ToJSONKey Architecture where
|
|
|
|
toJSONKey = genericToJSONKey defaultJSONKeyOptions
|
|
|
|
|
|
|
|
instance FromJSONKey Architecture where
|
|
|
|
fromJSONKey = genericFromJSONKey defaultJSONKeyOptions
|
|
|
|
|
|
|
|
instance ToJSONKey Tool where
|
|
|
|
toJSONKey = genericToJSONKey defaultJSONKeyOptions
|
|
|
|
|
|
|
|
instance FromJSONKey Tool where
|
|
|
|
fromJSONKey = genericFromJSONKey defaultJSONKeyOptions
|
|
|
|
|
2020-08-10 20:22:48 +00:00
|
|
|
instance ToJSON TarDir where
|
|
|
|
toJSON (RealDir p) = toJSON p
|
|
|
|
toJSON (RegexDir r) = object ["RegexDir" .= r]
|
2020-08-06 11:28:20 +00:00
|
|
|
|
2020-08-10 20:22:48 +00:00
|
|
|
instance FromJSON TarDir where
|
|
|
|
parseJSON v = realDir v <|> regexDir v
|
|
|
|
where
|
|
|
|
realDir = withText "TarDir" $ \t -> do
|
|
|
|
fp <- parseJSON (String t)
|
|
|
|
pure (RealDir fp)
|
|
|
|
regexDir = withObject "TarDir" $ \o -> do
|
|
|
|
r <- o .: "RegexDir"
|
|
|
|
pure $ RegexDir r
|
2020-11-20 17:37:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
instance ToJSON VersionCmp where
|
|
|
|
toJSON = String . versionCmpToText
|
|
|
|
|
|
|
|
instance FromJSON VersionCmp where
|
|
|
|
parseJSON = withText "VersionCmp" $ \t -> do
|
|
|
|
case MP.parse versionCmpP "" t of
|
|
|
|
Right r -> pure r
|
|
|
|
Left e -> fail (MP.errorBundlePretty e)
|
|
|
|
|
2022-12-03 16:15:13 +00:00
|
|
|
instance ToJSON ByteString where
|
|
|
|
toJSON = toJSON . E.decodeUtf8With E.lenientDecode
|
|
|
|
|
|
|
|
instance FromJSON ByteString where
|
|
|
|
parseJSON = withText "ByteString" $ \t -> pure $ E.encodeUtf8 t
|
|
|
|
|
2020-11-20 17:37:48 +00:00
|
|
|
versionCmpToText :: VersionCmp -> T.Text
|
|
|
|
versionCmpToText (VR_gt ver') = "> " <> prettyV ver'
|
|
|
|
versionCmpToText (VR_gteq ver') = ">= " <> prettyV ver'
|
|
|
|
versionCmpToText (VR_lt ver') = "< " <> prettyV ver'
|
|
|
|
versionCmpToText (VR_lteq ver') = "<= " <> prettyV ver'
|
|
|
|
versionCmpToText (VR_eq ver') = "== " <> prettyV ver'
|
|
|
|
|
|
|
|
versionCmpP :: MP.Parsec Void T.Text VersionCmp
|
|
|
|
versionCmpP =
|
|
|
|
fmap VR_gt (MP.try $ MPC.space *> MP.chunk ">" *> MPC.space *> versioningEnd)
|
|
|
|
<|> fmap
|
|
|
|
VR_gteq
|
|
|
|
(MP.try $ MPC.space *> MP.chunk ">=" *> MPC.space *> versioningEnd)
|
|
|
|
<|> fmap
|
|
|
|
VR_lt
|
|
|
|
(MP.try $ MPC.space *> MP.chunk "<" *> MPC.space *> versioningEnd)
|
|
|
|
<|> fmap
|
|
|
|
VR_lteq
|
|
|
|
(MP.try $ MPC.space *> MP.chunk "<=" *> MPC.space *> versioningEnd)
|
|
|
|
<|> fmap
|
|
|
|
VR_eq
|
|
|
|
(MP.try $ MPC.space *> MP.chunk "==" *> MPC.space *> versioningEnd)
|
|
|
|
<|> fmap
|
|
|
|
VR_eq
|
|
|
|
(MP.try $ MPC.space *> versioningEnd)
|
|
|
|
|
|
|
|
instance ToJSON VersionRange where
|
|
|
|
toJSON = String . verRangeToText
|
|
|
|
|
|
|
|
verRangeToText :: VersionRange -> T.Text
|
|
|
|
verRangeToText (SimpleRange cmps) =
|
|
|
|
let inner = foldr1 (\x y -> x <> " && " <> y)
|
|
|
|
(versionCmpToText <$> NE.toList cmps)
|
|
|
|
in "( " <> inner <> " )"
|
|
|
|
verRangeToText (OrRange cmps range) =
|
2021-03-11 16:03:51 +00:00
|
|
|
let left = verRangeToText (SimpleRange cmps)
|
2020-11-20 17:37:48 +00:00
|
|
|
right = verRangeToText range
|
|
|
|
in left <> " || " <> right
|
|
|
|
|
|
|
|
instance FromJSON VersionRange where
|
|
|
|
parseJSON = withText "VersionRange" $ \t -> do
|
|
|
|
case MP.parse versionRangeP "" t of
|
|
|
|
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)
|
2021-03-11 16:03:51 +00:00
|
|
|
<|> fmap (SimpleRange . pure) versionCmpP
|
2020-11-20 17:37:48 +00:00
|
|
|
|
|
|
|
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)
|
2021-03-11 16:03:51 +00:00
|
|
|
<*> MP.try (MP.many (MPC.space *> MP.chunk "&&" *> MPC.space *> versionCmpP))
|
2020-11-20 17:37:48 +00:00
|
|
|
<* 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
|
|
|
|
Nothing -> "unknown_versioning"
|
|
|
|
|
|
|
|
instance FromJSONKey (Maybe VersionRange) where
|
|
|
|
fromJSONKey = FromJSONKeyTextParser $ \t ->
|
|
|
|
if t == T.pack "unknown_versioning" then pure Nothing else just t
|
|
|
|
where
|
|
|
|
just t = case MP.parse versionRangeP "" t of
|
|
|
|
Right x -> pure $ Just x
|
|
|
|
Left e -> fail $ "Failure in (Maybe VersionRange) (FromJSONKey)" <> MP.errorBundlePretty e
|
2021-05-14 21:09:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Requirements
|
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''DownloadInfo
|
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''VersionInfo
|
2023-10-24 16:35:41 +00:00
|
|
|
|
|
|
|
instance FromJSON GHCupInfo where
|
|
|
|
parseJSON = withObject "GHCupInfo" $ \o -> do
|
|
|
|
toolRequirements' <- o .:? "toolRequirements"
|
2023-11-13 08:53:24 +00:00
|
|
|
metadataUpdate <- o .:? "metadataUpdate"
|
2023-10-24 16:35:41 +00:00
|
|
|
ghcupDownloads' <- o .: "ghcupDownloads"
|
2023-11-13 08:53:24 +00:00
|
|
|
pure (GHCupInfo (fromMaybe mempty toolRequirements') ghcupDownloads' metadataUpdate)
|
2023-10-24 16:35:41 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
instance ToJSON URLSource where
|
|
|
|
toJSON = toJSON . fromURLSource
|
|
|
|
|
2021-05-14 21:09:45 +00:00
|
|
|
deriveJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''Key
|
2023-10-21 12:20:59 +00:00
|
|
|
deriveJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''Modifier
|
2022-12-03 16:15:13 +00:00
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel, unwrapUnaryRecords = True } ''Port
|
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel, unwrapUnaryRecords = True } ''Host
|
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''UserInfo
|
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' (T.unpack . T.toLower) . T.stripPrefix (T.pack "authority") . T.pack $ str' } ''Authority
|
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''DownloadMirror
|
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''DownloadMirrors
|
2022-06-04 21:15:06 +00:00
|
|
|
|
|
|
|
instance FromJSON URLSource where
|
|
|
|
parseJSON v =
|
|
|
|
parseGHCupURL v
|
2023-10-24 16:35:41 +00:00
|
|
|
<|> parseStackURL v
|
2022-06-04 21:15:06 +00:00
|
|
|
<|> parseOwnSourceLegacy v
|
|
|
|
<|> parseOwnSourceNew1 v
|
|
|
|
<|> parseOwnSourceNew2 v
|
|
|
|
<|> parseOwnSpec v
|
|
|
|
<|> legacyParseAddSource v
|
|
|
|
<|> newParseAddSource v
|
2023-10-24 16:35:41 +00:00
|
|
|
-- new since Stack SetupInfo
|
|
|
|
<|> parseOwnSpecNew v
|
|
|
|
<|> parseOwnSourceNew3 v
|
|
|
|
<|> newParseAddSource2 v
|
|
|
|
-- more lenient versions
|
|
|
|
<|> parseOwnSpecLenient v
|
|
|
|
<|> parseOwnSourceLenient v
|
|
|
|
<|> parseAddSourceLenient v
|
|
|
|
-- simplified list
|
|
|
|
<|> parseNewUrlSource v
|
|
|
|
<|> parseNewUrlSource' v
|
2022-06-04 21:15:06 +00:00
|
|
|
where
|
2023-10-24 16:35:41 +00:00
|
|
|
convert'' :: Either GHCupInfo URI -> Either (Either GHCupInfo SetupInfo) URI
|
|
|
|
convert'' (Left gi) = Left (Left gi)
|
|
|
|
convert'' (Right uri) = Right uri
|
|
|
|
|
2022-06-04 21:15:06 +00:00
|
|
|
parseOwnSourceLegacy = withObject "URLSource" $ \o -> do
|
|
|
|
r :: URI <- o .: "OwnSource"
|
|
|
|
pure (OwnSource [Right r])
|
|
|
|
parseOwnSourceNew1 = withObject "URLSource" $ \o -> do
|
|
|
|
r :: [URI] <- o .: "OwnSource"
|
|
|
|
pure (OwnSource (fmap Right r))
|
|
|
|
parseOwnSourceNew2 = withObject "URLSource" $ \o -> do
|
|
|
|
r :: [Either GHCupInfo URI] <- o .: "OwnSource"
|
2023-10-24 16:35:41 +00:00
|
|
|
pure (OwnSource (convert'' <$> r))
|
2022-06-04 21:15:06 +00:00
|
|
|
parseOwnSpec = withObject "URLSource" $ \o -> do
|
|
|
|
r :: GHCupInfo <- o .: "OwnSpec"
|
2023-10-24 16:35:41 +00:00
|
|
|
pure (OwnSpec $ Left r)
|
2022-06-04 21:15:06 +00:00
|
|
|
parseGHCupURL = withObject "URLSource" $ \o -> do
|
|
|
|
_ :: [Value] <- o .: "GHCupURL"
|
|
|
|
pure GHCupURL
|
2023-10-24 16:35:41 +00:00
|
|
|
parseStackURL = withObject "URLSource" $ \o -> do
|
|
|
|
_ :: [Value] <- o .: "StackSetupURL"
|
|
|
|
pure StackSetupURL
|
2022-06-04 21:15:06 +00:00
|
|
|
legacyParseAddSource = withObject "URLSource" $ \o -> do
|
|
|
|
r :: Either GHCupInfo URI <- o .: "AddSource"
|
2023-10-24 16:35:41 +00:00
|
|
|
pure (AddSource [convert'' r])
|
2022-06-04 21:15:06 +00:00
|
|
|
newParseAddSource = withObject "URLSource" $ \o -> do
|
|
|
|
r :: [Either GHCupInfo URI] <- o .: "AddSource"
|
2023-10-24 16:35:41 +00:00
|
|
|
pure (AddSource (convert'' <$> r))
|
|
|
|
|
|
|
|
-- new since Stack SetupInfo
|
|
|
|
parseOwnSpecNew = withObject "URLSource" $ \o -> do
|
|
|
|
r :: Either GHCupInfo SetupInfo <- o .: "OwnSpec"
|
|
|
|
pure (OwnSpec r)
|
|
|
|
parseOwnSourceNew3 = withObject "URLSource" $ \o -> do
|
|
|
|
r :: [Either (Either GHCupInfo SetupInfo) URI] <- o .: "OwnSource"
|
|
|
|
pure (OwnSource r)
|
|
|
|
newParseAddSource2 = withObject "URLSource" $ \o -> do
|
|
|
|
r :: [Either (Either GHCupInfo SetupInfo) URI] <- o .: "AddSource"
|
2022-06-04 21:15:06 +00:00
|
|
|
pure (AddSource r)
|
|
|
|
|
2023-10-24 16:35:41 +00:00
|
|
|
-- more lenient versions
|
|
|
|
parseOwnSpecLenient = withObject "URLSource" $ \o -> do
|
|
|
|
spec :: Object <- o .: "OwnSpec"
|
|
|
|
OwnSpec <$> lenientInfoParser spec
|
|
|
|
parseOwnSourceLenient = withObject "URLSource" $ \o -> do
|
|
|
|
mown :: Array <- o .: "OwnSource"
|
|
|
|
OwnSource . toList <$> mapM lenientInfoUriParser mown
|
|
|
|
parseAddSourceLenient = withObject "URLSource" $ \o -> do
|
|
|
|
madd :: Array <- o .: "AddSource"
|
|
|
|
AddSource . toList <$> mapM lenientInfoUriParser madd
|
|
|
|
|
|
|
|
-- simplified
|
|
|
|
parseNewUrlSource = withArray "URLSource" $ \a -> do
|
|
|
|
SimpleList . toList <$> mapM parseJSON a
|
|
|
|
parseNewUrlSource' v' = SimpleList .(:[]) <$> parseJSON v'
|
|
|
|
|
|
|
|
|
|
|
|
lenientInfoUriParser :: Value -> Parser (Either (Either GHCupInfo SetupInfo) URI)
|
|
|
|
lenientInfoUriParser (Object o) = Left <$> lenientInfoParser o
|
|
|
|
lenientInfoUriParser v@(String _) = Right <$> parseJSON v
|
|
|
|
lenientInfoUriParser _ = fail "Unexpected json in lenientInfoUriParser"
|
|
|
|
|
|
|
|
|
|
|
|
lenientInfoParser :: Object -> Parser (Either GHCupInfo SetupInfo)
|
|
|
|
lenientInfoParser o = do
|
|
|
|
setup_info :: Maybe Object <- o .:? "setup-info"
|
|
|
|
case setup_info of
|
|
|
|
Nothing -> do
|
|
|
|
r <- parseJSON (Object o)
|
|
|
|
pure $ Left r
|
|
|
|
Just setup_info' -> do
|
|
|
|
r <- parseJSON (Object setup_info')
|
|
|
|
pure $ Right r
|
|
|
|
|
|
|
|
instance FromJSON NewURLSource where
|
|
|
|
parseJSON v = uri v <|> url v <|> gi v <|> si v
|
|
|
|
where
|
|
|
|
uri = withText "NewURLSource" $ \t -> NewURI <$> parseJSON (String t)
|
|
|
|
url = withText "NewURLSource" $ \t -> case T.unpack t of
|
|
|
|
"GHCupURL" -> pure NewGHCupURL
|
|
|
|
"StackSetupURL" -> pure NewStackSetupURL
|
|
|
|
t' -> fail $ "Unexpected text value in NewURLSource: " <> t'
|
|
|
|
gi = withObject "NewURLSource" $ \o -> do
|
|
|
|
ginfo :: GHCupInfo <- o .: "ghcup-info"
|
|
|
|
pure $ NewGHCupInfo ginfo
|
|
|
|
|
|
|
|
si = withObject "NewURLSource" $ \o -> do
|
|
|
|
sinfo :: SetupInfo <- o .: "setup-info"
|
|
|
|
pure $ NewSetupInfo sinfo
|
|
|
|
|
|
|
|
|
2023-10-21 12:20:59 +00:00
|
|
|
instance FromJSON KeyCombination where
|
|
|
|
parseJSON v = proper v <|> simple v
|
|
|
|
where
|
|
|
|
simple = withObject "KeyCombination" $ \o -> do
|
|
|
|
k <- parseJSON (Object o)
|
|
|
|
pure (KeyCombination k [])
|
|
|
|
proper = withObject "KeyCombination" $ \o -> do
|
|
|
|
k <- o .: "Key"
|
|
|
|
m <- o .: "Mods"
|
|
|
|
pure $ KeyCombination k m
|
|
|
|
|
|
|
|
instance ToJSON KeyCombination where
|
|
|
|
toJSON (KeyCombination k m) = object ["Key" .= k, "Mods" .= m]
|
|
|
|
|
|
|
|
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
|
2022-06-04 21:15:06 +00:00
|
|
|
deriveJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' T.unpack . T.stripPrefix (T.pack "u-") . T.pack . kebab $ str' } ''UserSettings
|
2023-10-21 12:20:59 +00:00
|
|
|
deriveToJSON defaultOptions { fieldLabelModifier = kebab } ''Settings
|