content: module Juvix.Compiler.Pipeline.Root
    ( module Juvix.Compiler.Pipeline.Root,
      module Juvix.Compiler.Pipeline.Root.Base,
    )
  where
  
  import Control.Exception qualified as IO
  import Control.Monad.Catch qualified as M
  import Juvix.Compiler.Pipeline.EntryPoint
  import Juvix.Compiler.Pipeline.Package.IO
  import Juvix.Compiler.Pipeline.Root.Base
  import Juvix.Data.Effect.TaggedLock
  import Juvix.Extra.Paths qualified as Paths
  import Juvix.Prelude
  
  readPackageRootIO :: (Members '[TaggedLock, Reader EntryPoint, EmbedIO] r) => Root -> Sem r Package
  readPackageRootIO root = readPackageIO (root ^. rootRootDir) (root ^. rootBuildDir)
  
  findRootAndChangeDir ::
    forall r.
    (Members '[TaggedLock, EmbedIO] r) =>
    Maybe (Path Abs Dir) ->
    Maybe (Path Abs Dir) ->
    Path Abs Dir ->
    Sem r Root
  findRootAndChangeDir minputFileDir mbuildDir _rootInvokeDir = do
    let handleErr :: IO.SomeException -> Sem r x
        handleErr (err :: IO.SomeException) = do
          putStrLn "Something went wrong when looking for the root of the project"
          putStrLn (pack (IO.displayException err))
          exitFailure
    r <- M.catch go handleErr
    runFilesIO ensureGlobalPackage
    return r
    where
      possiblePaths :: Path Abs Dir -> [Path Abs Dir]
      possiblePaths p = p : toList (parents p)
  
      findPackageFile :: (Members '[EmbedIO] r') => Sem r' (Maybe (Path Abs File))
      findPackageFile = do
        let cwd = fromMaybe _rootInvokeDir minputFileDir
            findPackageFile' = findFile (possiblePaths cwd)
        yamlFile <- findPackageFile' Paths.juvixYamlFile
        pFile <- findPackageFile' Paths.packageFilePath
        return (pFile <|> yamlFile)
  
      go :: Sem r Root
      go = do
        l <- findPackageFile
        case l of
          Nothing -> do
            let cwd = fromMaybe _rootInvokeDir minputFileDir
            packageBaseRootDir <- runFilesIO globalPackageBaseRoot
            _rootSomeRoot <-
              if
                  | isPathPrefix packageBaseRootDir cwd ->
                      return
                        SomeRoot
                          { _someRootDir = packageBaseRootDir,
                            _someRootType = GlobalPackageBase
                          }
                  | otherwise -> do
                      r <- runFilesIO globalRoot
                      return
                        SomeRoot
                          { _someRootDir = r,
                            _someRootType = GlobalStdlib
                          }
            let _rootBuildDir = getBuildDir mbuildDir
            return Root {..}
          Just pkgPath -> do
            packageDescriptionRootDir <- runFilesIO globalPackageDescriptionRoot
            let _rootBuildDir = getBuildDir mbuildDir
                rootdir = parent pkgPath
                _rootSomeRoot =
                  SomeRoot
                    { _someRootDir = rootdir,
                      _someRootType =
                        if
                            | isPathPrefix packageDescriptionRootDir rootdir -> GlobalPackageDescription
                            | otherwise -> LocalPackage
                    }
            return Root {..}
  
  getBuildDir :: Maybe (Path Abs Dir) -> BuildDir
  getBuildDir mbuildDirOpt = case mbuildDirOpt of
    Nothing -> DefaultBuildDir
    Just p -> CustomBuildDir (Abs p)
  