packages feed

hix-0.9.0: lib/Hix/Managed/Cabal/Data/ContextHackageRepo.hs

module Hix.Managed.Cabal.Data.ContextHackageRepo where

import Data.Aeson (FromJSON (parseJSON), withObject, withText, (.:))
import Distribution.Pretty (Pretty (pretty))
import Exon (exon)
import Text.PrettyPrint

import Hix.Class.EncodeNix (EncodeNix (encodeNix))
import Hix.Data.NixExpr (Expr (..), ExprAttr (..))
import Hix.Managed.Cabal.Data.HackageLocation (HackagePassword (HackagePassword), HackageUser)
import Hix.Managed.Cabal.Data.HackageRepo (HackageDescription, HackageIndexState, HackageName)
import Hix.NixExpr (mkAttrs, single, singleOpt)
import Hix.Pretty (field, prettyFieldsV, prettyText)

newtype ContextHackageLocation =
  ContextHackageLocation Text
  deriving stock (Eq, Show)
  deriving newtype (IsString, Ord, FromJSON, EncodeNix)

instance Pretty ContextHackageLocation where
  pretty = prettyText . coerce

data ContextHackagePassword =
  -- | Password was intended to be printed, most likely in a test.
  PasswordUnobscured HackagePassword
  |
  PasswordPlain HackagePassword
  |
  PasswordEnvVar Text
  |
  PasswordExec Text
  deriving stock (Eq, Show)

instance Pretty ContextHackagePassword where
  pretty = \case
    PasswordUnobscured (HackagePassword pw) -> prettyText pw
    PasswordPlain _ -> "<password>"
    PasswordEnvVar var -> prettyText var <+> brackets (text "env-var")
    PasswordExec exe -> prettyText exe <+> brackets (text "exec")

instance EncodeNix ContextHackagePassword where
  encodeNix = \case
    PasswordUnobscured (HackagePassword pw) -> ExprString pw
    PasswordPlain _ -> ExprString "<password>"
    PasswordEnvVar var -> structured "env-var" var
    PasswordExec exe -> structured "exec" exe
    where
      structured t value =
        ExprAttrs [
          ExprAttr "type" (ExprString t),
          ExprAttr {name = "value", value = ExprString value}
        ]

instance FromJSON ContextHackagePassword where
  parseJSON v =
    withText "ContextHackagePassword" plain v
    <|>
    withObject "ContextHackagePassword" typed v
    where
      typed o = do
        value <- o .: "value"
        o .: "type" >>= \case
          ("plain" :: Text) -> plain value
          "env-var" -> pure (PasswordEnvVar value)
          "exec" -> pure (PasswordExec value)
          t -> fail [exon|Invalid value for Hackage password type: ##{t}|]

      plain = pure . PasswordPlain . HackagePassword

data ContextHackageRepo =
  ContextHackageRepo {
    name :: HackageName,
    description :: Maybe HackageDescription,
    enable :: Maybe Bool,
    location :: Maybe ContextHackageLocation,
    user :: Maybe HackageUser,
    password :: Maybe ContextHackagePassword,
    secure :: Maybe Bool,
    keys :: Maybe (NonEmpty Text),
    indexState :: Maybe HackageIndexState,
    solver :: Maybe Bool,
    publish :: Maybe Bool
  }
  deriving stock (Eq, Show, Generic)
  deriving anyclass (FromJSON)

instance Pretty ContextHackageRepo where
  pretty ContextHackageRepo {..} =
    prettyFieldsV [
      field "name" name,
      field "description" description,
      field "enable" enable,
      field "location" location,
      field "user" user,
      field "password" password,
      field "secure" secure,
      field "keys" keys,
      field "indexState" indexState,
      field "solver" solver,
      field "publish" publish
    ]

instance EncodeNix ContextHackageRepo where
  encodeNix =
    ExprAttrs . mkAttrs [
      single "name" (.name),
      singleOpt "description" (.description),
      singleOpt "enable" (.enable),
      singleOpt "location" (.location),
      singleOpt "user" (.user),
      singleOpt "password" (.password),
      singleOpt "secure" (.secure),
      singleOpt "keys" (.keys),
      singleOpt "indexState" (.indexState),
      singleOpt "solver" (.solver),
      singleOpt "publish" (.publish)
    ]

contextHackageRepo :: HackageName -> ContextHackageRepo
contextHackageRepo name =
  ContextHackageRepo {
    name,
    description = Nothing,
    enable = Nothing,
    location = Nothing,
    user = Nothing,
    password = Nothing,
    secure = Nothing,
    keys = Nothing,
    indexState = Nothing,
    solver = Nothing,
    publish = Nothing
  }