-- | Manage lambdabot's state files. There are three relevant directories: -- -- * local: @./State/@ (configurable, see `outputDir`) -- * home: @~/.lambdabot/State/@ -- * data: relative to the data directory of the @lambdabot@ package. -- -- Files are stored locally if the directory exists; otherwise, in the home -- directory. When reading a state file, and the file exists in the data -- directory but nowhere else, then it is picked up from the data directory. module Lambdabot.File ( stateDir , findLBFileForReading , findLBFileForWriting , findOrCreateLBFile , findLBFile -- deprecated , outputDir ) where import Lambdabot.Config import Lambdabot.Config.Core import Lambdabot.Monad import Lambdabot.Util import Control.Applicative import Control.Monad import System.Directory import System.FilePath lambdabot :: FilePath lambdabot = ".lambdabot" -- | Locate state directory. Returns the local directory if it exists, -- and the home directory otherwise. stateDir :: LB FilePath stateDir = do -- look locally output <- getConfig outputDir b <- io $ doesDirectoryExist output if b then return output else homeDir homeDir :: LB FilePath homeDir = do output <- getConfig outputDir home <- io getHomeDirectory return $ home lambdabot output -- | Look for the file in the local, home, and data directories. findLBFileForReading :: FilePath -> LB (Maybe FilePath) findLBFileForReading f = do state <- stateDir home <- homeDir output <- getConfig outputDir rodir <- getConfig dataDir findFirstFile [state f, home f, rodir output f] -- | Return file name for writing state. The file will reside in the -- state directory (`stateDir`), and `findLBFileForWriting` ensures that -- the state directory exists. findLBFileForWriting :: FilePath -> LB FilePath findLBFileForWriting f = do state <- stateDir -- ensure that the directory exists io $ createDirectoryIfMissing True state success <- io $ doesDirectoryExist state when (not success) $ fail $ concat ["Unable to create directory ", state] return $ state f findFirstFile :: [FilePath] -> LB (Maybe FilePath) findFirstFile [] = return Nothing findFirstFile (path:ps) = do b <- io $ doesFileExist path if b then return (Just path) else findFirstFile ps {-# DEPRECATED findLBFile "Use `findLBFileForReading` or `findLBFileForWriting` instead" #-} -- | Try to find a pre-existing file, searching first in the local or home -- directory (but not in the data directory) findLBFile :: FilePath -> LB (Maybe String) findLBFile f = do state <- stateDir home <- homeDir findFirstFile [state f, home f] -- | This returns the same file name as `findLBFileForWriting`. -- If the file does not exist, it is either copied from the data (or home) -- directory, if a copy is found there; otherwise, an empty file is -- created instead. findOrCreateLBFile :: FilePath -> LB String findOrCreateLBFile f = do outFile <- findLBFileForWriting f b <- io $ doesFileExist outFile when (not b) $ do -- the file does not exist; populate it from home or data directory b <- findLBFileForReading f case b of Nothing -> io $ writeFile outFile "" Just roFile -> io $ copyFile roFile outFile return outFile