packages feed

morloc-0.33.0: library/Morloc/Config.hs

{-|
Module      : Morloc.Config
Description : Handle local configuration
Copyright   : (c) Zebulun Arendsee, 2020
License     : GPL-3
Maintainer  : zbwrnz@gmail.com
Stability   : experimental
-}
module Morloc.Config
  ( Config(..)
  , loadMorlocConfig
  , loadDefaultMorlocConfig
  , buildPoolCallBase
  , getDefaultConfigFilepath
  , getDefaultMorlocTmpDir
  , makeLibSourceString
  ) where

import Data.Aeson (FromJSON(..), (.!=), (.:?), withObject)
import Morloc.Data.Doc
import Morloc.Namespace
import qualified Morloc.Language as ML
import qualified Data.HashMap.Strict as H
import qualified Data.Yaml.Config as YC
import qualified Morloc.Data.Text as MT
import qualified Morloc.System as MS
import Morloc.Pretty ()


getDefaultConfigFilepath :: IO Path
getDefaultConfigFilepath =
  MS.getHomeDirectory |>> MS.appendPath (Path ".morloc/config")

instance FromJSON Path where
  parseJSON = fmap Path . parseJSON

-- FIXME: remove this chronic multiplication
instance FromJSON Config where
  parseJSON =
    withObject "object" $ \o ->
      Config
        <$> fmap Path (o .:? "home" .!= "$HOME/.morloc")
        <*> fmap Path (o .:? "library" .!= "$HOME/.morloc/lib")
        <*> fmap Path (o .:? "tmpdir" .!= "$HOME/.morloc/tmp" )
        <*> fmap Path (o .:? "lang_python3" .!= "python3")
        <*> fmap Path (o .:? "lang_R" .!= "Rscript")
        <*> fmap Path (o .:? "lang_perl" .!= "perl")

-- | Load the default Morloc configuration, ignoring any local configurations.
loadDefaultMorlocConfig :: IO Config
loadDefaultMorlocConfig = do
  defaults <- defaultFields
  return $
    Config
      (Path $ defaults H.! "home")
      (Path $ defaults H.! "library")
      (Path $ defaults H.! "tmpdir")
      (Path "python") -- lang_python3
      (Path "Rscript") -- lang_R
      (Path "perl") -- lang_perl

-- | Load a Morloc config file. If no file is given (i.e., Nothing), then the
-- default configuration will be used.
loadMorlocConfig :: Maybe Path -> IO Config
loadMorlocConfig Nothing = do
  defaults <- defaultFields
  MS.loadYamlConfig
    Nothing 
    (YC.useCustomEnv defaults)
    loadDefaultMorlocConfig
loadMorlocConfig (Just configFile) = do
  configExists <- MS.fileExists configFile
  defaults <- defaultFields
  if configExists
    then
      MS.loadYamlConfig
        (Just [configFile])
        (YC.useCustomEnv defaults)
        loadDefaultMorlocConfig
    else
      loadMorlocConfig Nothing 

-- | Create the base call to a pool (without arguments)
-- For example:
--   ./pool.R 1 --
--   ./pool.py 1 --
--   ./pool-cpp.out 1 --
--   ./pool.R 1 [1,2,3] true
buildPoolCallBase
  :: Config
  -> Maybe Lang
  -> Int
  -> Maybe [MDoc]
buildPoolCallBase _ (Just CLang) i =
  Just ["./" <> pretty (ML.makeExecutableName CLang "pool"), pretty i]
buildPoolCallBase _ (Just CppLang) i =
  Just ["./" <> pretty (ML.makeExecutableName CppLang "pool"), pretty i]
buildPoolCallBase c (Just RLang) i =
  Just [pretty (configLangR c), pretty (ML.makeExecutableName RLang "pool"), pretty i]
buildPoolCallBase c (Just Python3Lang) i =
  Just [pretty (configLangPython3 c), pretty (ML.makeExecutableName Python3Lang "pool"), pretty i]
buildPoolCallBase _ _ _ = Nothing -- FIXME: add error handling

-- A key value map
defaultFields :: IO (H.HashMap MT.Text MT.Text)
defaultFields = do
  home <- fmap unPath getDefaultMorlocHome
  lib <- fmap unPath getDefaultMorlocLibrary
  tmp <- fmap unPath getDefaultMorlocTmpDir
  return $ H.fromList [("home", home), ("library", lib), ("tmpdir", tmp)]

-- | Get the Morloc home directory (absolute path)
getDefaultMorlocHome :: IO Path
getDefaultMorlocHome = MS.getHomeDirectory |>> MS.appendPath (Path ".morloc")

-- | Get the Morloc library directory (absolute path). Usually this will be a
-- folder inside the home directory.
getDefaultMorlocLibrary :: IO Path
getDefaultMorlocLibrary = MS.getHomeDirectory |>> MS.appendPath (Path ".morloc/lib")

-- | Get the Morloc default temporary directory. This will store generated
-- SPARQL queries and rdf dumps that can be used in debugging.
getDefaultMorlocTmpDir :: IO Path
getDefaultMorlocTmpDir = MS.getHomeDirectory |>> MS.appendPath (Path ".morloc/tmp")

-- | Get a source string for a library module. This will 1) remove the
-- user-specific home directory and 2) replace '/' separators with '.'. An
-- input of Nothing indicates the input is a local file or STDIN.
makeLibSourceString :: Maybe Path -> MorlocMonad (Maybe Path)
makeLibSourceString (Just (Path x)) = do
  homedir <- liftIO getDefaultMorlocLibrary
  let x' = maybe x id (MT.stripPrefix (unPath homedir) x)
  let x'' = maybe x' id (MT.stripPrefix "/" x')
  return . Just . Path . MT.replace "/" "__" . MT.replace "." "_" $ x''
makeLibSourceString Nothing = return Nothing