packages feed

pfile-0.1.0.0: src/PFile/Env.hs

{- |
Module:      PFile.Env
Copyright:   (c) 2024 Illia Shkroba
License:     BSD3
Maintainer:  Illia Shkroba <is@pjwstk.edu.pl>
Stability:   unstable
Portability: non-portable (Non-Unix systems are not supported)

Types and functions for managing PFile's environment.
-}

{-# LANGUAGE BlockArguments    #-}
{-# LANGUAGE NamedFieldPuns    #-}
{-# LANGUAGE OverloadedStrings #-}

module PFile.Env
  ( resolve
  , description
  , Options (..)
  , Env (..)
  ) where

import           Control.Monad.Trans.Maybe (MaybeT (..))
import           PFile.Error               (onIOError)
import           PFile.Path                ((<//>))
import qualified PFile.Path                as Path
import           Protolude
import           System.Directory
  ( XdgDirectory (..)
  , doesDirectoryExist
  , getXdgDirectory
  , makeAbsolute
  )
import           System.Environment        (lookupEnv)

-- | Deduce PFile's 'dataHomeDirPath' in the following order:
--
-- * Lookup in "$PFILE_DATA_HOME" environment variable if exists.
-- * Use ".pfile" directory from the current working directory if exists.
-- * Use "$XDG_DATA_HOME/pfile" directory.
--
-- Based on the 'dataHomeDirPath' other fields of 'Env' are resolved.
--
-- @since 0.1.0.0
resolve :: MonadIO m => Options -> m Env
resolve options@Options {verbose} = liftIO do
  resolved <-
    runMaybeT . asum . map MaybeT $
    [ lookupEnv "PFILE_DATA_HOME"
    , doesDirectoryExist ".pfile" `onIOError` pure False
      <&> bool Nothing (Just ".pfile")
    ]
  dataHomeDirPath <-
    maybe (getXdgDirectory XdgData "pfile") makeAbsolute resolved
    <&> Path.Absolute
  pure
    Env
      { dataHomeDirPath
      , profilesHomeDirPath = dataHomeDirPath <//> "profiles"
      , currentLinkPath = dataHomeDirPath <//> "current"
      , PFile.Env.print = bool (const $ pure ()) putErrLn verbose
      , options
      }

-- | Describe an 'Env'.
--
-- @since 0.1.0.0
description :: Env -> Text
description Env {dataHomeDirPath}
  =  "PFile uses data home directory: "
  <> Path.showAbsolute dataHomeDirPath <> "."

-- | 'Env' options.
--
-- @since 0.1.0.0
newtype Options
  = Options
      { verbose :: Bool
      -- ^ Whether logging should be enabled.
      }

-- | PFile's environment that effects its behavior.
--
-- @since 0.1.0.0
data Env
  = Env
      { dataHomeDirPath     :: !Path.Absolute
      -- ^ PFile's home directory.
      , profilesHomeDirPath :: !Path.Absolute
      -- ^ Profiles home directory.
      , currentLinkPath     :: !Path.Absolute
      -- ^ Path to a current profile's link.
      , print               :: !(Text -> IO ())
      -- ^ Function used by logging functions.
      , options             :: !Options
      -- ^ 'Options' that were used to create the 'Env'.
      }