content: {-# LANGUAGE NoImplicitPrelude     #-}
  {-# LANGUAGE DuplicateRecordFields #-}
  {-# LANGUAGE NoFieldSelectors      #-}
  {-# LANGUAGE OverloadedStrings     #-}
  
  {-|
  Module      : Stack.Types.Nix
  Description : Nix types.
  License     : BSD-3-Clause
  
  Nix types.
  -}
  
  module Stack.Types.Nix
    ( NixOpts (..)
    , NixOptsMonoid (..)
    , nixAddGCRootsArgName
    , nixEnableArgName
    , nixInitFileArgName
    , nixPackagesArgName
    , nixPathArgName
    , nixPureShellArgName
    , nixShellOptsArgName
    ) where
  
  import           Data.Aeson.Types ( FromJSON (..) )
  import           Data.Aeson.WarningParser
                     ( WithJSONWarnings, (..:?), withObjectWarnings )
  import           Generics.Deriving.Monoid ( mappenddefault, memptydefault )
  import           Stack.Prelude
  
  -- | Nix configuration. Parameterize by snapshot type to avoid cyclic
  -- dependency.
  data NixOpts = NixOpts
    { enable :: !Bool
    , pureShell :: !Bool
    , packages :: ![Text]
      -- ^ The system packages to be installed in the environment before it runs
    , initFile :: !(Maybe FilePath)
      -- ^ The path of a file containing preconfiguration of the environment
      -- (e.g shell.nix)
    , shellOptions :: ![Text]
      -- ^ Options to be given to the nix-shell command line
    , addGCRoots :: !Bool
      -- ^ Should we register gc roots so running nix-collect-garbage doesn't
      -- remove nix dependencies
    }
    deriving Show
  
  -- | An uninterpreted representation of nix options.
  -- Configurations may be "cascaded" using mappend (left-biased).
  data NixOptsMonoid = NixOptsMonoid
    { enable :: !(First Bool)
      -- ^ Is using nix-shell enabled?
    , pureShell :: !(First Bool)
      -- ^ Should the nix-shell be pure
    , packages :: !(First [Text])
      -- ^ System packages to use (given to nix-shell)
    , initFile :: !(First FilePath)
      -- ^ The path of a file containing preconfiguration of the environment (e.g
      -- shell.nix)
    , shellOptions :: !(First [Text])
      -- ^ Options to be given to the nix-shell command line
    , path :: !(First [Text])
      -- ^ Override parts of NIX_PATH (notably \'nixpkgs\')
    , addGCRoots :: !FirstFalse
      -- ^ Should we register gc roots so running nix-collect-garbage doesn't
      -- remove nix dependencies
    }
    deriving (Eq, Generic, Show)
  
  -- | Decode uninterpreted nix options from JSON/YAML.
  instance FromJSON (WithJSONWarnings NixOptsMonoid) where
    parseJSON = withObjectWarnings "NixOptsMonoid" $ \o -> do
      enable        <- First <$> o ..:? nixEnableArgName
      pureShell     <- First <$> o ..:? nixPureShellArgName
      packages      <- First <$> o ..:? nixPackagesArgName
      initFile      <- First <$> o ..:? nixInitFileArgName
      shellOptions  <- First <$> o ..:? nixShellOptsArgName
      path          <- First <$> o ..:? nixPathArgName
      addGCRoots    <- FirstFalse <$> o ..:? nixAddGCRootsArgName
      pure NixOptsMonoid
        { enable
        , pureShell
        , packages
        , initFile
        , shellOptions
        , path
        , addGCRoots
        }
  
  -- | Left-biased combine Nix options
  instance Semigroup NixOptsMonoid where
    (<>) = mappenddefault
  
  -- | Left-biased combine Nix options
  instance Monoid NixOptsMonoid where
    mempty = memptydefault
    mappend = (<>)
  
  -- | Nix enable argument name.
  nixEnableArgName :: Text
  nixEnableArgName = "enable"
  
  -- | Nix run in pure shell argument name.
  nixPureShellArgName :: Text
  nixPureShellArgName = "pure"
  
  -- | Nix packages (build inputs) argument name.
  nixPackagesArgName :: Text
  nixPackagesArgName = "packages"
  
  -- | shell.nix file path argument name.
  nixInitFileArgName :: Text
  nixInitFileArgName = "shell-file"
  
  -- | Extra options for the nix-shell command argument name.
  nixShellOptsArgName :: Text
  nixShellOptsArgName = "nix-shell-options"
  
  -- | NIX_PATH override argument name
  nixPathArgName :: Text
  nixPathArgName = "path"
  
  -- | Add GC roots arg name
  nixAddGCRootsArgName :: Text
  nixAddGCRootsArgName = "add-gc-roots"
  