-- for IdempotentIO import Control.Monad (when) -- for Link import Control.Monad.Loops (andM) import System.Posix.Files (fileExist, getSymbolicLinkStatus, isSymbolicLink, readSymbolicLink, createSymbolicLink) import System.Directory (getHomeDirectory, getCurrentDirectory) class IdempotentIO thing where check :: thing -> IO Bool set, ensure :: thing -> IO () ensure thing = do isSet <- check thing when (not isSet) $ set thing data Link = Link { fromPath :: String , toPath :: String , qualifyPath :: String -> String } instance IdempotentIO Link where check link = andM [ fileExist $ qualified fromPath , fmap isSymbolicLink . getSymbolicLinkStatus $ qualified fromPath , fmap (== qualified toPath) . readSymbolicLink $ qualified fromPath ] where qualified path = qualifyPath link $ path link set link = createSymbolicLink (qualified toPath) (qualified fromPath) where qualified path = qualifyPath link $ path link main = ensure $ Link "foo" "bar" id