-- | The information from Paths_shake cleaned up
module Development.Shake.Internal.Paths(
    shakeVersionString,
    initDataDirectory,
    hasManualData, copyManualData,
    readDataFileHTML
    ) where

import Paths_shake
import Control.Exception
import Control.Monad.Extra
import Data.Version
import System.Directory
import System.FilePath
import System.Info.Extra
import System.IO.Unsafe
import System.Environment.Extra
import General.Extra
import Data.Functor
import qualified Data.ByteString.Lazy as LBS
import Prelude


shakeVersionString :: String
shakeVersionString :: String
shakeVersionString = Version -> String
showVersion Version
version


-- We want getDataFileName to be relative to the current directory on program startup,
-- even if we issue a change directory command. Therefore, first call caches, future ones read.
{-# NOINLINE dataDirs #-}
dataDirs :: [String]
dataDirs :: [String]
dataDirs = IO [String] -> [String]
forall a. IO a -> a
unsafePerformIO (IO [String] -> [String]) -> IO [String] -> [String]
forall a b. (a -> b) -> a -> b
$ do
    String
datdir <- IO String
getDataDir
    String
exedir <- String -> String
takeDirectory (String -> String) -> IO String -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO String
getExecutablePath IO String -> (IOException -> IO String) -> IO String
forall a. IO a -> (IOException -> IO a) -> IO a
`catchIO` \_ -> String -> IO String
forall (m :: * -> *) a. Monad m => a -> m a
return ""
    String
curdir <- IO String
getCurrentDirectory
    [String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return ([String] -> IO [String]) -> [String] -> IO [String]
forall a b. (a -> b) -> a -> b
$ [String
datdir] [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String
exedir | String
exedir String -> String -> Bool
forall a. Eq a => a -> a -> Bool
/= ""] [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String
curdir]


-- The data files may be located relative to the current directory, if so cache it in advance
initDataDirectory :: IO ()
initDataDirectory :: IO ()
initDataDirectory = IO [String] -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO [String] -> IO ()) -> IO [String] -> IO ()
forall a b. (a -> b) -> a -> b
$ [String] -> IO [String]
forall a. a -> IO a
evaluate [String]
dataDirs


getDataFile :: FilePath -> IO FilePath
getDataFile :: String -> IO String
getDataFile file :: String
file = do
    let poss :: [String]
poss = (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String -> String -> String
</> String
file) [String]
dataDirs
    [String]
res <- (String -> IO Bool) -> [String] -> IO [String]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM String -> IO Bool
doesFileExist_ [String]
poss
    case [String]
res of
        [] -> String -> IO String
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO String) -> String -> IO String
forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ ("Could not find data file " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
file String -> String -> String
forall a. [a] -> [a] -> [a]
++ ", looked in:") String -> [String] -> [String]
forall a. a -> [a] -> [a]
: (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ("  " String -> String -> String
forall a. [a] -> [a] -> [a]
++) [String]
poss
        x :: String
x:_ -> String -> IO String
forall (m :: * -> *) a. Monad m => a -> m a
return String
x

hasDataFile :: FilePath -> IO Bool
hasDataFile :: String -> IO Bool
hasDataFile file :: String
file = (String -> IO Bool) -> [String] -> IO Bool
forall (m :: * -> *) a. Monad m => (a -> m Bool) -> [a] -> m Bool
anyM (\dir :: String
dir -> String -> IO Bool
doesFileExist_ (String -> IO Bool) -> String -> IO Bool
forall a b. (a -> b) -> a -> b
$ String
dir String -> String -> String
</> String
file) [String]
dataDirs


readDataFileHTML :: FilePath -> IO LBS.ByteString
readDataFileHTML :: String -> IO ByteString
readDataFileHTML file :: String
file = String -> IO ByteString
LBS.readFile (String -> IO ByteString) -> IO String -> IO ByteString
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< String -> IO String
getDataFile ("html" String -> String -> String
</> String
file)


manualFiles :: [FilePath]
manualFiles :: [String]
manualFiles = (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ("docs/manual" String -> String -> String
</>) ["Build.hs","main.c","constants.c","constants.h","build" String -> String -> String
<.> if Bool
isWindows then "bat" else "sh"]

hasManualData :: IO Bool
hasManualData :: IO Bool
hasManualData = (String -> IO Bool) -> [String] -> IO Bool
forall (m :: * -> *) a. Monad m => (a -> m Bool) -> [a] -> m Bool
allM String -> IO Bool
hasDataFile [String]
manualFiles

copyManualData :: FilePath -> IO ()
copyManualData :: String -> IO ()
copyManualData dest :: String
dest = do
    String -> IO ()
createDirectoryRecursive String
dest
    [String] -> (String -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [String]
manualFiles ((String -> IO ()) -> IO ()) -> (String -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \file :: String
file -> do
        String
src <- String -> IO String
getDataFile String
file
        String -> String -> IO ()
copyFile String
src (String
dest String -> String -> String
</> String -> String
takeFileName String
file)