{-# LANGUAGE CPP #-}

module Development.Shake.Internal.History.Symlink(
    copyFileLink,
    createLinkMaybe
    ) where

import Control.Monad.Extra
import General.Extra
import System.Directory
import System.FilePath


#ifdef mingw32_HOST_OS
import Foreign.Ptr
import Foreign.C.String
#else
import System.Posix.Files(createLink)
#endif

createLinkMaybe :: FilePath -> FilePath -> IO (Maybe String)

#ifdef mingw32_HOST_OS

#ifdef x86_64_HOST_ARCH
#define CALLCONV ccall
#else
#define CALLCONV stdcall
#endif

foreign import CALLCONV unsafe "Windows.h CreateHardLinkW " c_CreateHardLinkW :: CWString -> CWString -> Ptr () -> IO Bool

createLinkMaybe from to = withCWString from $ \cfrom -> withCWString to $ \cto -> do
    res <- c_CreateHardLinkW cto cfrom nullPtr
    pure $ if res then Nothing else Just "CreateHardLink failed."

#else

createLinkMaybe from to = handleIO (pure . Just . show) $ createLink from to >> pure Nothing

#endif


copyFileLink :: Bool -> FilePath -> FilePath -> IO ()
copyFileLink useSymlink from to = do
    createDirectoryRecursive $ takeDirectory to
    removeFile_ to
    if not useSymlink then copyFile from to else do
        b <- createLinkMaybe from to
        whenJust b $ \_ ->
            copyFile from to
        -- making files read only stops them from inadvertently mutating the cache
        forM_ [from, to] $ \x -> do
            perm <- getPermissions x
            setPermissions x perm{writable=False}