serokell/importify

View on GitHub
src/Importify/Environment.hs

Summary

Maintainability
Test Coverage
{-# LANGUAGE ConstraintKinds        #-}
{-# LANGUAGE FlexibleContexts       #-}
{-# LANGUAGE FlexibleInstances      #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses  #-}
{-# LANGUAGE TemplateHaskell        #-}

-- | This module contains enrinment for @importify cache@ command
-- which is running inside @ReaderT env IO@ monad.

module Importify.Environment
       ( -- * Base monad for @importify cache@ command
         RIO (..)

         -- * Environment for @importify cache@ command
       , CacheEnvironment (..)
       , HasGhcIncludeDir
       , HasPathToImportify
       , HasSaveSources
       , ghcIncludeDir
       , pathToImportify
       , pathToSymbols
       , saveSources

         -- * Runner for cache commend
       , runCache
       ) where

import           Universum

import           Lens.Micro.Platform (SimpleGetter, makeLensesWith, to)
import           Path                (Abs, Dir, Path, (</>))
import           Path.IO             (getCurrentDir)

import           Extended.Lens.TH    (fieldsVerboseLensRules)
import           Importify.Path      (doInsideDir, importifyPath, symbolsPath)
import           Importify.Stack     (ghcIncludePath, stackProjectRoot)

-- | 'ReaderT' + 'IO' monad described here:
-- https://www.fpcomplete.com/blog/2017/07/the-rio-monad
newtype RIO env a = RIO
    { runRIO :: ReaderT env IO a
    } deriving ( Functor, Applicative, Monad, MonadIO
               , MonadReader env, MonadThrow, MonadCatch, MonadMask)

-- | Environment for @importify cache@ command.
data CacheEnvironment = CacheEnvironment
    { -- | Path to local @.importify@ folder
      _pathToImportify :: !(Path Abs Dir)

      -- | Path to GHC .h files
    , _ghcIncludeDir   :: !(Maybe (Path Abs Dir))

      -- | 'True' if unpacked sources should be stored locally as well
    , _saveSources     :: !Bool
    }

makeLensesWith fieldsVerboseLensRules ''CacheEnvironment

type HasPathToImportify env = HasPolyPathToImportify env (Path Abs Dir)
type HasGhcIncludeDir   env = HasPolyGhcIncludeDir   env (Maybe (Path Abs Dir))
type HasSaveSources     env = HasPolySaveSources     env Bool

-- | Getter of @~\/path\/to\/project\/.importify\/symbols@ folder.
pathToSymbols :: HasPathToImportify env => SimpleGetter env (Path Abs Dir)
pathToSymbols = pathToImportify.to (</> symbolsPath)

-- | Run @importify cache@ command. This function takes current
-- project directory and searches for ghc include path.
runCache :: Bool -> RIO CacheEnvironment () -> IO ()
runCache _saveSources cacheAction = do
    projectRoot         <- runMaybeT stackProjectRoot
    case projectRoot of
        Nothing              -> return ()  -- error is reported inside 'stackProjectRoot'
        Just projectRootPath -> doInsideDir projectRootPath cacheRunner
  where
    cacheRunner :: IO ()
    cacheRunner = do
        projectPath         <- getCurrentDir
        let _pathToImportify = projectPath </> importifyPath
        _ghcIncludeDir      <- runMaybeT ghcIncludePath
        usingReaderT CacheEnvironment{..} $ runRIO cacheAction