{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE DeriveGeneric #-}
{- |
Module      :  Neovim.BuildTool
Description :  Utilities and types to manage build tool dependent things
Copyright   :  (c) Sebastian Witte
License     :  Apache-2.0

Maintainer  :  woozletoff@gmail.com
Stability   :  experimental
Portability :  GHC

-}
module Neovim.BuildTool
    where

import Neovim
import Data.List (isSuffixOf)
import Control.Monad.IO.Class
import GHC.Generics
import Data.Yaml
import System.Directory
import System.FilePath (takeDirectory, (</>))

data BuildTool
    = Stack
    | Cabal CabalType
    | Shake
    | Make
    | Cmake
    | Ninja
    | Scons
    | Custom
    deriving (Int -> BuildTool -> ShowS
[BuildTool] -> ShowS
BuildTool -> String
(Int -> BuildTool -> ShowS)
-> (BuildTool -> String)
-> ([BuildTool] -> ShowS)
-> Show BuildTool
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [BuildTool] -> ShowS
$cshowList :: [BuildTool] -> ShowS
show :: BuildTool -> String
$cshow :: BuildTool -> String
showsPrec :: Int -> BuildTool -> ShowS
$cshowsPrec :: Int -> BuildTool -> ShowS
Show, ReadPrec [BuildTool]
ReadPrec BuildTool
Int -> ReadS BuildTool
ReadS [BuildTool]
(Int -> ReadS BuildTool)
-> ReadS [BuildTool]
-> ReadPrec BuildTool
-> ReadPrec [BuildTool]
-> Read BuildTool
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [BuildTool]
$creadListPrec :: ReadPrec [BuildTool]
readPrec :: ReadPrec BuildTool
$creadPrec :: ReadPrec BuildTool
readList :: ReadS [BuildTool]
$creadList :: ReadS [BuildTool]
readsPrec :: Int -> ReadS BuildTool
$creadsPrec :: Int -> ReadS BuildTool
Read, BuildTool -> BuildTool -> Bool
(BuildTool -> BuildTool -> Bool)
-> (BuildTool -> BuildTool -> Bool) -> Eq BuildTool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: BuildTool -> BuildTool -> Bool
$c/= :: BuildTool -> BuildTool -> Bool
== :: BuildTool -> BuildTool -> Bool
$c== :: BuildTool -> BuildTool -> Bool
Eq, Eq BuildTool
Eq BuildTool
-> (BuildTool -> BuildTool -> Ordering)
-> (BuildTool -> BuildTool -> Bool)
-> (BuildTool -> BuildTool -> Bool)
-> (BuildTool -> BuildTool -> Bool)
-> (BuildTool -> BuildTool -> Bool)
-> (BuildTool -> BuildTool -> BuildTool)
-> (BuildTool -> BuildTool -> BuildTool)
-> Ord BuildTool
BuildTool -> BuildTool -> Bool
BuildTool -> BuildTool -> Ordering
BuildTool -> BuildTool -> BuildTool
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: BuildTool -> BuildTool -> BuildTool
$cmin :: BuildTool -> BuildTool -> BuildTool
max :: BuildTool -> BuildTool -> BuildTool
$cmax :: BuildTool -> BuildTool -> BuildTool
>= :: BuildTool -> BuildTool -> Bool
$c>= :: BuildTool -> BuildTool -> Bool
> :: BuildTool -> BuildTool -> Bool
$c> :: BuildTool -> BuildTool -> Bool
<= :: BuildTool -> BuildTool -> Bool
$c<= :: BuildTool -> BuildTool -> Bool
< :: BuildTool -> BuildTool -> Bool
$c< :: BuildTool -> BuildTool -> Bool
compare :: BuildTool -> BuildTool -> Ordering
$ccompare :: BuildTool -> BuildTool -> Ordering
$cp1Ord :: Eq BuildTool
Ord, (forall x. BuildTool -> Rep BuildTool x)
-> (forall x. Rep BuildTool x -> BuildTool) -> Generic BuildTool
forall x. Rep BuildTool x -> BuildTool
forall x. BuildTool -> Rep BuildTool x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep BuildTool x -> BuildTool
$cfrom :: forall x. BuildTool -> Rep BuildTool x
Generic)

instance ToJSON BuildTool
instance FromJSON BuildTool

data CabalType
    = Plain
    | Sandbox
    | NewBuild
    deriving (Int -> CabalType -> ShowS
[CabalType] -> ShowS
CabalType -> String
(Int -> CabalType -> ShowS)
-> (CabalType -> String)
-> ([CabalType] -> ShowS)
-> Show CabalType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [CabalType] -> ShowS
$cshowList :: [CabalType] -> ShowS
show :: CabalType -> String
$cshow :: CabalType -> String
showsPrec :: Int -> CabalType -> ShowS
$cshowsPrec :: Int -> CabalType -> ShowS
Show, ReadPrec [CabalType]
ReadPrec CabalType
Int -> ReadS CabalType
ReadS [CabalType]
(Int -> ReadS CabalType)
-> ReadS [CabalType]
-> ReadPrec CabalType
-> ReadPrec [CabalType]
-> Read CabalType
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [CabalType]
$creadListPrec :: ReadPrec [CabalType]
readPrec :: ReadPrec CabalType
$creadPrec :: ReadPrec CabalType
readList :: ReadS [CabalType]
$creadList :: ReadS [CabalType]
readsPrec :: Int -> ReadS CabalType
$creadsPrec :: Int -> ReadS CabalType
Read, CabalType -> CabalType -> Bool
(CabalType -> CabalType -> Bool)
-> (CabalType -> CabalType -> Bool) -> Eq CabalType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: CabalType -> CabalType -> Bool
$c/= :: CabalType -> CabalType -> Bool
== :: CabalType -> CabalType -> Bool
$c== :: CabalType -> CabalType -> Bool
Eq, Eq CabalType
Eq CabalType
-> (CabalType -> CabalType -> Ordering)
-> (CabalType -> CabalType -> Bool)
-> (CabalType -> CabalType -> Bool)
-> (CabalType -> CabalType -> Bool)
-> (CabalType -> CabalType -> Bool)
-> (CabalType -> CabalType -> CabalType)
-> (CabalType -> CabalType -> CabalType)
-> Ord CabalType
CabalType -> CabalType -> Bool
CabalType -> CabalType -> Ordering
CabalType -> CabalType -> CabalType
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: CabalType -> CabalType -> CabalType
$cmin :: CabalType -> CabalType -> CabalType
max :: CabalType -> CabalType -> CabalType
$cmax :: CabalType -> CabalType -> CabalType
>= :: CabalType -> CabalType -> Bool
$c>= :: CabalType -> CabalType -> Bool
> :: CabalType -> CabalType -> Bool
$c> :: CabalType -> CabalType -> Bool
<= :: CabalType -> CabalType -> Bool
$c<= :: CabalType -> CabalType -> Bool
< :: CabalType -> CabalType -> Bool
$c< :: CabalType -> CabalType -> Bool
compare :: CabalType -> CabalType -> Ordering
$ccompare :: CabalType -> CabalType -> Ordering
$cp1Ord :: Eq CabalType
Ord, Int -> CabalType
CabalType -> Int
CabalType -> [CabalType]
CabalType -> CabalType
CabalType -> CabalType -> [CabalType]
CabalType -> CabalType -> CabalType -> [CabalType]
(CabalType -> CabalType)
-> (CabalType -> CabalType)
-> (Int -> CabalType)
-> (CabalType -> Int)
-> (CabalType -> [CabalType])
-> (CabalType -> CabalType -> [CabalType])
-> (CabalType -> CabalType -> [CabalType])
-> (CabalType -> CabalType -> CabalType -> [CabalType])
-> Enum CabalType
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: CabalType -> CabalType -> CabalType -> [CabalType]
$cenumFromThenTo :: CabalType -> CabalType -> CabalType -> [CabalType]
enumFromTo :: CabalType -> CabalType -> [CabalType]
$cenumFromTo :: CabalType -> CabalType -> [CabalType]
enumFromThen :: CabalType -> CabalType -> [CabalType]
$cenumFromThen :: CabalType -> CabalType -> [CabalType]
enumFrom :: CabalType -> [CabalType]
$cenumFrom :: CabalType -> [CabalType]
fromEnum :: CabalType -> Int
$cfromEnum :: CabalType -> Int
toEnum :: Int -> CabalType
$ctoEnum :: Int -> CabalType
pred :: CabalType -> CabalType
$cpred :: CabalType -> CabalType
succ :: CabalType -> CabalType
$csucc :: CabalType -> CabalType
Enum, (forall x. CabalType -> Rep CabalType x)
-> (forall x. Rep CabalType x -> CabalType) -> Generic CabalType
forall x. Rep CabalType x -> CabalType
forall x. CabalType -> Rep CabalType x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep CabalType x -> CabalType
$cfrom :: forall x. CabalType -> Rep CabalType x
Generic)

instance ToJSON CabalType
instance FromJSON CabalType

newtype Directory = Directory { Directory -> String
getDirectory :: FilePath }
    deriving (Int -> Directory -> ShowS
[Directory] -> ShowS
Directory -> String
(Int -> Directory -> ShowS)
-> (Directory -> String)
-> ([Directory] -> ShowS)
-> Show Directory
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Directory] -> ShowS
$cshowList :: [Directory] -> ShowS
show :: Directory -> String
$cshow :: Directory -> String
showsPrec :: Int -> Directory -> ShowS
$cshowsPrec :: Int -> Directory -> ShowS
Show, Directory -> Directory -> Bool
(Directory -> Directory -> Bool)
-> (Directory -> Directory -> Bool) -> Eq Directory
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Directory -> Directory -> Bool
$c/= :: Directory -> Directory -> Bool
== :: Directory -> Directory -> Bool
$c== :: Directory -> Directory -> Bool
Eq, Eq Directory
Eq Directory
-> (Directory -> Directory -> Ordering)
-> (Directory -> Directory -> Bool)
-> (Directory -> Directory -> Bool)
-> (Directory -> Directory -> Bool)
-> (Directory -> Directory -> Bool)
-> (Directory -> Directory -> Directory)
-> (Directory -> Directory -> Directory)
-> Ord Directory
Directory -> Directory -> Bool
Directory -> Directory -> Ordering
Directory -> Directory -> Directory
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Directory -> Directory -> Directory
$cmin :: Directory -> Directory -> Directory
max :: Directory -> Directory -> Directory
$cmax :: Directory -> Directory -> Directory
>= :: Directory -> Directory -> Bool
$c>= :: Directory -> Directory -> Bool
> :: Directory -> Directory -> Bool
$c> :: Directory -> Directory -> Bool
<= :: Directory -> Directory -> Bool
$c<= :: Directory -> Directory -> Bool
< :: Directory -> Directory -> Bool
$c< :: Directory -> Directory -> Bool
compare :: Directory -> Directory -> Ordering
$ccompare :: Directory -> Directory -> Ordering
$cp1Ord :: Eq Directory
Ord)


-- | If the monadic boolean predicate returns true, wrap the given object in a
-- 'Just' constructor, otherwise return 'Nothing'.
partialM :: Monad m => (a -> m Bool) -> a -> m (Maybe a)
partialM :: (a -> m Bool) -> a -> m (Maybe a)
partialM a -> m Bool
fp a
a = a -> m Bool
fp a
a m Bool -> (Bool -> m (Maybe a)) -> m (Maybe a)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Bool
True -> Maybe a -> m (Maybe a)
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> Maybe a
forall a. a -> Maybe a
Just a
a)
    Bool
False -> Maybe a -> m (Maybe a)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe a
forall a. Maybe a
Nothing

-- | Create 'Just' a 'Directory' value if the given filepath exists and
-- otherwise return 'Nothing'. This method does not create an actual directory
-- on your file system.
mkDirectory :: MonadIO io => FilePath -> io (Maybe Directory)
mkDirectory :: String -> io (Maybe Directory)
mkDirectory String
mdir =
    (String -> Directory) -> Maybe String -> Maybe Directory
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap String -> Directory
Directory (Maybe String -> Maybe Directory)
-> io (Maybe String) -> io (Maybe Directory)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (String -> io Bool) -> String -> io (Maybe String)
forall (m :: * -> *) a.
Monad m =>
(a -> m Bool) -> a -> m (Maybe a)
partialM (IO Bool -> io Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> io Bool) -> (String -> IO Bool) -> String -> io Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO Bool
doesDirectoryExist) String
mdir

newtype File = File { File -> String
getFile :: FilePath }
    deriving (Int -> File -> ShowS
[File] -> ShowS
File -> String
(Int -> File -> ShowS)
-> (File -> String) -> ([File] -> ShowS) -> Show File
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [File] -> ShowS
$cshowList :: [File] -> ShowS
show :: File -> String
$cshow :: File -> String
showsPrec :: Int -> File -> ShowS
$cshowsPrec :: Int -> File -> ShowS
Show, File -> File -> Bool
(File -> File -> Bool) -> (File -> File -> Bool) -> Eq File
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: File -> File -> Bool
$c/= :: File -> File -> Bool
== :: File -> File -> Bool
$c== :: File -> File -> Bool
Eq, Eq File
Eq File
-> (File -> File -> Ordering)
-> (File -> File -> Bool)
-> (File -> File -> Bool)
-> (File -> File -> Bool)
-> (File -> File -> Bool)
-> (File -> File -> File)
-> (File -> File -> File)
-> Ord File
File -> File -> Bool
File -> File -> Ordering
File -> File -> File
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: File -> File -> File
$cmin :: File -> File -> File
max :: File -> File -> File
$cmax :: File -> File -> File
>= :: File -> File -> Bool
$c>= :: File -> File -> Bool
> :: File -> File -> Bool
$c> :: File -> File -> Bool
<= :: File -> File -> Bool
$c<= :: File -> File -> Bool
< :: File -> File -> Bool
$c< :: File -> File -> Bool
compare :: File -> File -> Ordering
$ccompare :: File -> File -> Ordering
$cp1Ord :: Eq File
Ord)

-- | Create 'Just' a 'File' value if the given file exists and is not a
-- directory. Otherwise return 'Nothing'. This function does not alter your
-- filesystem.
mkFile :: MonadIO io => Maybe Directory -> FilePath -> io (Maybe File)
mkFile :: Maybe Directory -> String -> io (Maybe File)
mkFile Maybe Directory
mdir String
mfile =
    let f :: String
f = String -> (Directory -> String) -> Maybe Directory -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
mfile (\Directory
d -> Directory -> String
getDirectory Directory
d String -> ShowS
</> String
mfile) Maybe Directory
mdir
    in (String -> File) -> Maybe String -> Maybe File
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap String -> File
File (Maybe String -> Maybe File)
-> io (Maybe String) -> io (Maybe File)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (String -> io Bool) -> String -> io (Maybe String)
forall (m :: * -> *) a.
Monad m =>
(a -> m Bool) -> a -> m (Maybe a)
partialM (IO Bool -> io Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> io Bool) -> (String -> IO Bool) -> String -> io Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO Bool
doesFileExist) String
f

-- | Calculate the list of all parent directories for the given directory. This
-- function also returns the initially specified directory.
thisAndParentDirectories :: Directory -> [Directory]
thisAndParentDirectories :: Directory -> [Directory]
thisAndParentDirectories Directory
dir
    | Directory
parentDir Directory -> Directory -> Bool
forall a. Eq a => a -> a -> Bool
== Directory
dir = [Directory
dir]
    | Bool
otherwise = Directory
dir Directory -> [Directory] -> [Directory]
forall a. a -> [a] -> [a]
: Directory -> [Directory]
thisAndParentDirectories Directory
parentDir
  where
    parentDir :: Directory
parentDir = String -> Directory
Directory (String -> Directory) -> ShowS -> String -> Directory
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  ShowS
takeDirectory (String -> Directory) -> String -> Directory
forall a b. (a -> b) -> a -> b
$ Directory -> String
getDirectory Directory
dir


-- | Given a list of build tool identifier functions, apply these to all the
-- given directories and return the value of the first function that returns a
-- 'BuildTool' value or 'Nothing' if no function ever returns a 'BuildTool'.
-- The identifier functions and directories are tried in the order as supplied
-- to this function.
determineProjectSettings
    :: MonadIO io
    => [Directory -> io (Maybe BuildTool)]
    -> [Directory]
    -> io (Maybe (BuildTool, Directory))
determineProjectSettings :: [Directory -> io (Maybe BuildTool)]
-> [Directory] -> io (Maybe (BuildTool, Directory))
determineProjectSettings [Directory -> io (Maybe BuildTool)]
identifiers = [Directory -> io (Maybe BuildTool)]
-> [Directory] -> io (Maybe (BuildTool, Directory))
go [Directory -> io (Maybe BuildTool)]
identifiers
  where
    go :: [Directory -> io (Maybe BuildTool)]
-> [Directory] -> io (Maybe (BuildTool, Directory))
go [Directory -> io (Maybe BuildTool)]
_ []             = Maybe (BuildTool, Directory) -> io (Maybe (BuildTool, Directory))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (BuildTool, Directory)
forall a. Maybe a
Nothing
    go [] (Directory
_:[Directory]
ps)        = [Directory -> io (Maybe BuildTool)]
-> [Directory] -> io (Maybe (BuildTool, Directory))
go [Directory -> io (Maybe BuildTool)]
identifiers [Directory]
ps
    go (Directory -> io (Maybe BuildTool)
i:[Directory -> io (Maybe BuildTool)]
is) pps :: [Directory]
pps@(Directory
p:[Directory]
_) = Directory -> io (Maybe BuildTool)
i Directory
p io (Maybe BuildTool)
-> (Maybe BuildTool -> io (Maybe (BuildTool, Directory)))
-> io (Maybe (BuildTool, Directory))
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
                        Just BuildTool
buildTool -> Maybe (BuildTool, Directory) -> io (Maybe (BuildTool, Directory))
forall (m :: * -> *) a. Monad m => a -> m a
return ((BuildTool, Directory) -> Maybe (BuildTool, Directory)
forall a. a -> Maybe a
Just (BuildTool
buildTool, Directory
p))
                        Maybe BuildTool
Nothing -> [Directory -> io (Maybe BuildTool)]
-> [Directory] -> io (Maybe (BuildTool, Directory))
go [Directory -> io (Maybe BuildTool)]
is [Directory]
pps


-- | This list contains some build tool identifier functions for usual setups.
defaultProjectIdentifiers :: MonadIO io => [Directory -> io (Maybe BuildTool)]
defaultProjectIdentifiers :: [Directory -> io (Maybe BuildTool)]
defaultProjectIdentifiers =
    [ Directory -> io (Maybe BuildTool)
forall (io :: * -> *).
MonadIO io =>
Directory -> io (Maybe BuildTool)
maybeCabalSandbox, Directory -> io (Maybe BuildTool)
forall (io :: * -> *).
MonadIO io =>
Directory -> io (Maybe BuildTool)
maybeStack, Directory -> io (Maybe BuildTool)
forall (io :: * -> *).
MonadIO io =>
Directory -> io (Maybe BuildTool)
maybeCabal ]

-- | Same as 'determineProjectSettings' 'defaultProjetIdentifiers'.
guessProjectSettings :: MonadIO io
                     => [Directory]
                     -> io (Maybe (BuildTool, Directory))
guessProjectSettings :: [Directory] -> io (Maybe (BuildTool, Directory))
guessProjectSettings = [Directory -> io (Maybe BuildTool)]
-> [Directory] -> io (Maybe (BuildTool, Directory))
forall (io :: * -> *).
MonadIO io =>
[Directory -> io (Maybe BuildTool)]
-> [Directory] -> io (Maybe (BuildTool, Directory))
determineProjectSettings [Directory -> io (Maybe BuildTool)]
forall (io :: * -> *).
MonadIO io =>
[Directory -> io (Maybe BuildTool)]
defaultProjectIdentifiers


-- | Check if directory contains a @stack.yaml@ file and return 'Just' 'Stack'
-- in this case.
maybeStack :: MonadIO io => Directory -> io (Maybe BuildTool)
maybeStack :: Directory -> io (Maybe BuildTool)
maybeStack Directory
d = (File -> BuildTool) -> Maybe File -> Maybe BuildTool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (BuildTool -> File -> BuildTool
forall a b. a -> b -> a
const BuildTool
Stack) (Maybe File -> Maybe BuildTool)
-> io (Maybe File) -> io (Maybe BuildTool)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Directory -> String -> io (Maybe File)
forall (io :: * -> *).
MonadIO io =>
Maybe Directory -> String -> io (Maybe File)
mkFile (Directory -> Maybe Directory
forall a. a -> Maybe a
Just Directory
d) String
"stack.yaml"


-- | Check if the directory contains a @cabal.sandbox.config@ file and return
-- 'Just' ('Cabal' 'Sandbox') in that case.
maybeCabalSandbox :: MonadIO io => Directory -> io (Maybe BuildTool)
maybeCabalSandbox :: Directory -> io (Maybe BuildTool)
maybeCabalSandbox Directory
d = (File -> BuildTool) -> Maybe File -> Maybe BuildTool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (BuildTool -> File -> BuildTool
forall a b. a -> b -> a
const (CabalType -> BuildTool
Cabal CabalType
Sandbox))
    (Maybe File -> Maybe BuildTool)
-> io (Maybe File) -> io (Maybe BuildTool)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Directory -> String -> io (Maybe File)
forall (io :: * -> *).
MonadIO io =>
Maybe Directory -> String -> io (Maybe File)
mkFile (Directory -> Maybe Directory
forall a. a -> Maybe a
Just Directory
d) String
"cabal.sandbox.config"


-- | Check if the directory contains a cabal file and return 'Just' ('Cabal'
-- 'Plain') if present.
maybeCabal :: MonadIO io => Directory -> io (Maybe BuildTool)
maybeCabal :: Directory -> io (Maybe BuildTool)
maybeCabal Directory
d = do
    [String]
ls <-  IO [String] -> io [String]
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO [String] -> io [String])
-> (String -> IO [String]) -> String -> io [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO [String]
getDirectoryContents (String -> io [String]) -> String -> io [String]
forall a b. (a -> b) -> a -> b
$ Directory -> String
getDirectory Directory
d
    [String] -> io (Maybe BuildTool)
forall (m :: * -> *). MonadIO m => [String] -> m (Maybe BuildTool)
go ([String] -> io (Maybe BuildTool))
-> [String] -> io (Maybe BuildTool)
forall a b. (a -> b) -> a -> b
$ (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (String
".cabal" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isSuffixOf`)[String]
ls
  where
      go :: [String] -> m (Maybe BuildTool)
go [] = Maybe BuildTool -> m (Maybe BuildTool)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe BuildTool
forall a. Maybe a
Nothing
      go (String
f:[String]
fs) = Maybe Directory -> String -> m (Maybe File)
forall (io :: * -> *).
MonadIO io =>
Maybe Directory -> String -> io (Maybe File)
mkFile (Directory -> Maybe Directory
forall a. a -> Maybe a
Just Directory
d) String
f m (Maybe File)
-> (Maybe File -> m (Maybe BuildTool)) -> m (Maybe BuildTool)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
                    Maybe File
Nothing -> [String] -> m (Maybe BuildTool)
go [String]
fs
                    Just File
_ ->
                        -- TODO if cabal version >= 1.24(?), use NewBuild here?
                        Maybe BuildTool -> m (Maybe BuildTool)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe BuildTool -> m (Maybe BuildTool))
-> Maybe BuildTool -> m (Maybe BuildTool)
forall a b. (a -> b) -> a -> b
$ BuildTool -> Maybe BuildTool
forall a. a -> Maybe a
Just (CabalType -> BuildTool
Cabal CabalType
Plain)