    {-# LANGUAGE CPP #-}

    #ifdef FILE_EMBED
    {-# LANGUAGE TemplateHaskell #-}
    #endif

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

    import Control.Monad.Extra
    import Data.Version
    import System.FilePath
    import General.Extra
    import qualified Data.ByteString.Lazy as LBS
    import Paths_shake

    #ifdef FILE_EMBED
    import qualified Data.ByteString as BS
    import Data.FileEmbed
    #else
    import Control.Exception
    import System.Directory
    import System.Info.Extra
    import System.IO.Unsafe
    import System.Environment
    #endif

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

    #ifdef FILE_EMBED

    initDataDirectory :: IO ()
    initDataDirectory = pure ()

    htmlDataFiles :: [(FilePath, BS.ByteString)]
    htmlDataFiles =
      [ ("profile.html",  $(embedFile "html/profile.html"))
      , ("progress.html", $(embedFile "html/progress.html"))
      , ("shake.js",      $(embedFile "html/shake.js"))
      ]

    readDataFileHTML :: FilePath -> IO LBS.ByteString
    readDataFileHTML file = do
        case lookup file htmlDataFiles of
          Nothing -> fail $ "Could not find data file " ++ file ++ " in embedded data files!"
          Just x  -> pure (LBS.fromStrict x)

    manualDirData :: [(FilePath, BS.ByteString)]
    manualDirData = $(embedDir "docs/manual")

    hasManualData :: IO Bool
    hasManualData = pure True

    copyManualData :: FilePath -> IO ()
    copyManualData dest = do
        createDirectoryRecursive dest
        forM_ manualDirData $ \(file, bs) -> do
            BS.writeFile (dest </> file) bs

    #else
    -- 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 (f :: * -> *) a. Applicative f => a -> f a
    pure ""
        String
    curdir <- IO String
    getCurrentDirectory
        [String] -> IO [String]
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure ([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 (f :: * -> *) a. Applicative f => a -> f a
    pure 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
    </>) ["Shakefile.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)
    #endif