{-# LANGUAGE DataKinds #-}



-- | Finding files.

-- Lifted from Stack.

module Path.Find

  ( findFileUp

  ) where



import Control.Monad.Catch

import Control.Monad.IO.Class

import Data.List

import Path

import Path.IO



-- | Find the location of a file matching the given predicate.

findFileUp ::

     (MonadIO m, MonadThrow m)

  => Path Abs Dir -- ^ Start here.

  -> (Path Abs File -> Bool) -- ^ Predicate to match the file.

  -> Maybe (Path Abs Dir) -- ^ Do not ascend above this directory.

  -> m (Maybe (Path Abs File)) -- ^ Absolute file path.

findFileUp = findPathUp snd



-- | Find the location of a path matching the given predicate.

findPathUp ::

     (MonadIO m, MonadThrow m)

  => (([Path Abs Dir], [Path Abs File]) -> [Path Abs t])

              -- ^ Choose path type from pair.

  -> Path Abs Dir -- ^ Start here.

  -> (Path Abs t -> Bool) -- ^ Predicate to match the path.

  -> Maybe (Path Abs Dir) -- ^ Do not ascend above this directory.

  -> m (Maybe (Path Abs t)) -- ^ Absolute path.

findPathUp pathType dir p upperBound = do

  entries <- listDir dir

  case find p (pathType entries) of

    Just path -> return (Just path)

    Nothing

      | Just dir == upperBound -> return Nothing

      | parent dir == dir -> return Nothing

      | otherwise -> findPathUp pathType (parent dir) p upperBound