content: {-# LANGUAGE NoImplicitPrelude #-}
  {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE TemplateHaskell   #-}
  
  {-|
  Module      : Stack.Constants.Config
  License     : BSD-3-Clause
  -}
  
  module Stack.Constants.Config
    ( buildCachesDir
    , configCabalMod
    , configPackageProjectRoot
    , configSetupConfigMod
    , distDirFromDir
    , distRelativeDir
    , ghciDirL
    , hpcDirFromDir
    , hpcRelativeDir
    , imageStagingDir
    , objectInterfaceDirL
    , projectDockerSandboxDir
    , rootDistDirFromDir
    , setupConfigFromDir
    , templatesDir
    , testBuiltFile
    , testSuccessFile
    , workDirFromDir
    ) where
  
  import           Path ( (</>), mkRelDir, mkRelFile, parseRelDir )
  import           Stack.Constants ( relDirDist, relDirGhci, relDirHpc )
  import           Stack.Prelude
  import           Stack.Types.BuildConfig ( HasBuildConfig, configFileRootL )
  import           Stack.Types.Compiler ( compilerVersionString )
  import           Stack.Types.CompilerPaths ( compilerVersionL )
  import           Stack.Types.Config ( Config, HasConfig, stackRootL, workDirL )
  import           Stack.Types.EnvConfig
                     ( HasEnvConfig, platformGhcRelDir, useShaPathOnWindows )
  
  -- | Output .o/.hi directory.
  objectInterfaceDirL :: HasBuildConfig env => Getting r env (Path Abs Dir)
  objectInterfaceDirL = to $ \env -> -- FIXME is this idiomatic lens code?
    let workDir = view workDirL env
        configFileRoot = view configFileRootL env
    in  configFileRoot </> workDir </> $(mkRelDir "odir/")
  
  -- | GHCi files directory.
  ghciDirL :: HasBuildConfig env => Getting r env (Path Abs Dir)
  ghciDirL = to $ \env -> -- FIXME is this idiomatic lens code?
    let workDir = view workDirL env
        configFileRoot = view configFileRootL env
    in  configFileRoot </> workDir </> relDirGhci
  
  -- | The directory containing the files used for dirtiness check of source
  -- files.
  buildCachesDir ::
       (HasEnvConfig env, MonadReader env m, MonadThrow m)
    => Path Abs Dir  -- ^ Package directory.
    -> m (Path Abs Dir)
  buildCachesDir dir =
    fmap
      (</> $(mkRelDir "stack-build-caches"))
      (distDirFromDir dir)
  
  -- | The filename used to mark tests as having succeeded.
  testSuccessFile ::
       (HasEnvConfig env, MonadReader env m, MonadThrow m)
    => Path Abs Dir  -- ^ Package directory
    -> m (Path Abs File)
  testSuccessFile dir =
    fmap
      (</> $(mkRelFile "stack-test-success"))
      (distDirFromDir dir)
  
  -- | The filename used to mark tests as having built.
  testBuiltFile ::
       (HasEnvConfig env, MonadReader env m, MonadThrow m)
    => Path Abs Dir  -- ^ Package directory
    -> m (Path Abs File)
  testBuiltFile dir =
    fmap
      (</> $(mkRelFile "stack-test-built"))
      (distDirFromDir dir)
  
  -- | The filename used for modification check of a Cabal file.
  configCabalMod ::
       (HasEnvConfig env, MonadReader env m, MonadThrow m)
    => Path Abs Dir  -- ^ Package directory.
    -> m (Path Abs File)
  configCabalMod dir =
    fmap
      (</> $(mkRelFile "stack-cabal-mod"))
      (distDirFromDir dir)
  
  -- | The filename used for modification check of setup-config.
  configSetupConfigMod ::
       (HasEnvConfig env, MonadReader env m, MonadThrow m)
    => Path Abs Dir  -- ^ Package directory.
    -> m (Path Abs File)
  configSetupConfigMod dir =
    fmap
      (</> $(mkRelFile "stack-setup-config-mod"))
      (distDirFromDir dir)
  
  -- | The filename used for the project root from the last build of a package.
  configPackageProjectRoot ::
       (HasEnvConfig env, MonadReader env m, MonadThrow m)
    => Path Abs Dir  -- ^ Package directory.
    -> m (Path Abs File)
  configPackageProjectRoot dir =
    fmap
      (</> $(mkRelFile "stack-project-root"))
      (distDirFromDir dir)
  
  -- | Directory for HPC work.
  hpcDirFromDir ::
       (HasEnvConfig env, MonadReader env m, MonadThrow m)
    => Path Abs Dir  -- ^ Package directory.
    -> m (Path Abs Dir)
  hpcDirFromDir fp =
    fmap (fp </>) hpcRelativeDir
  
  -- | Relative location of directory for HPC work.
  hpcRelativeDir ::
       (HasEnvConfig env, MonadReader env m, MonadThrow m)
    => m (Path Rel Dir)
  hpcRelativeDir =
    fmap (</> relDirHpc) distRelativeDir
  
  -- | Package's setup-config storing Cabal configuration.
  setupConfigFromDir ::
       (HasEnvConfig env, MonadReader env m, MonadThrow m)
    => Path Abs Dir
    -> m (Path Abs File)
  setupConfigFromDir fp = do
    dist <- distDirFromDir fp
    pure $ dist </> $(mkRelFile "setup-config")
  
  -- | Package's build artifacts directory.
  distDirFromDir ::
       (HasEnvConfig env, MonadReader env m, MonadThrow m)
    => Path Abs Dir
    -> m (Path Abs Dir)
  distDirFromDir fp =
    fmap (fp </>) distRelativeDir
  
  -- | The directory containing all dist directories, including all
  -- different platform/compiler combinations.
  rootDistDirFromDir ::
       (HasConfig env, MonadReader env m)
    => Path Abs Dir
    -> m (Path Abs Dir)
  rootDistDirFromDir fp =
    fmap (fp </>) rootDistRelativeDir
  
  -- | Relative directory to the top dist directory, containing
  -- individual platform/compiler combinations as subdirs.
  rootDistRelativeDir ::
       (HasConfig env, MonadReader env m)
    => m (Path Rel Dir)
  rootDistRelativeDir = do
    workDir <- view workDirL
    pure $ workDir </> relDirDist
  
  -- | Package's working directory.
  workDirFromDir ::
       (HasConfig env, MonadReader env m)
    => Path Abs Dir
    -> m (Path Abs Dir)
  workDirFromDir fp = view $ workDirL.to (fp </>)
  
  -- | Directory for project templates.
  templatesDir :: Config -> Path Abs Dir
  templatesDir config = view stackRootL config </> $(mkRelDir "templates")
  
  -- | Relative location of build artifacts.
  distRelativeDir ::
       (HasEnvConfig env, MonadReader env m, MonadThrow m)
    => m (Path Rel Dir)
  distRelativeDir = do
    compilerVer <- view compilerVersionL
    platform <- platformGhcRelDir
    -- Compiler version: allows build artefacts to be distinguished by compiler
    -- version, which will also distinguish one Cabal version from another.
    compilerDir <- parseRelDir $ compilerVersionString compilerVer
    platformAndCompiler <- useShaPathOnWindows (platform </> compilerDir)
    allDist <- rootDistRelativeDir
    pure $ allDist </> platformAndCompiler
  
  -- | Docker sandbox from project root.
  projectDockerSandboxDir :: (HasConfig env, MonadReader env m)
    => Path Abs Dir      -- ^ Project root
    -> m (Path Abs Dir)  -- ^ Docker sandbox
  projectDockerSandboxDir projectRoot = do
    workDir <- view workDirL
    pure $ projectRoot </> workDir </> $(mkRelDir "docker/")
  
  -- | Image staging dir from project root.
  imageStagingDir ::
       (HasConfig env, MonadReader env m, MonadThrow m)
    => Path Abs Dir      -- ^ Project root
    -> Int               -- ^ Index of image
    -> m (Path Abs Dir)  -- ^ Docker sandbox
  imageStagingDir projectRoot imageIdx = do
    workDir <- view workDirL
    idxRelDir <- parseRelDir (show imageIdx)
    pure $ projectRoot </> workDir </> $(mkRelDir "image") </> idxRelDir
  