module Rakka.Storage.Repos ( findAllPagesInRevision , findChangedPagesAtRevision , loadPageInRepository ) where import Control.Monad import Data.List import qualified Data.Map as M import Data.Maybe import Data.Set (Set) import qualified Data.Set as S hiding (Set) import Data.Time import Network.HTTP.Lucu hiding (redirect) import Rakka.Page import Rakka.SystemConfig import Rakka.Utils import Rakka.W3CDateTime import Subversion.Types import Subversion.FileSystem import Subversion.FileSystem.DirEntry import Subversion.FileSystem.Revision import Subversion.FileSystem.Root import Subversion.Repository import System.FilePath.Posix findAllPagesInRevision :: Repository -> RevNum -> IO (Set PageName) findAllPagesInRevision repos rev = do fs <- getRepositoryFS repos withRevision fs rev $ do exists <- isDirectory root if exists then traverse root else return S.empty where root :: FilePath root = "/pages" traverse :: FilePath -> Rev (Set PageName) traverse dir = getDirEntries dir >>= mapM (traverse' dir) >>= return . S.unions traverse' :: FilePath -> DirEntry -> Rev (Set PageName) traverse' dir entry = let path = dir entName entry in do kind <- checkPath path case kind of NoNode -> return S.empty FileNode -> return $ S.singleton (decodePath path) DirNode -> traverse path decodePath :: FilePath -> PageName decodePath = decodePageName . makeRelative root . dropExtension findChangedPagesAtRevision :: Repository -> RevNum -> IO (Set PageName) findChangedPagesAtRevision repos rev = do fs <- getRepositoryFS repos withRevision fs rev $ getPathsChanged >>= return . foldl accumulatePages S.empty . map fst where accumulatePages :: Set PageName -> FilePath -> Set PageName accumulatePages s path | "/pages/" `isPrefixOf` path && ".page" `isSuffixOf` path = let encoded = makeRelative "/pages" $ dropExtension path name = decodePageName encoded in S.insert name s | otherwise = s loadPageInRepository :: Repository -> PageName -> Maybe RevNum -> IO (Maybe Page) loadPageInRepository repos name rev = do fs <- getRepositoryFS repos rev' <- case rev of Nothing -> getYoungestRev fs Just r -> return r withRevision fs rev' $ do exists <- isFile path case exists of True -> return . Just =<< loadPage' False -> return Nothing where path :: FilePath path = "pages" encodePageName name <.> "page" loadPage' :: Rev Page loadPage' = do redirect <- getNodeProp path "rakka:redirect" case redirect of Nothing -> loadPageEntity Just _ -> loadPageRedirect loadPageEntity :: Rev Page loadPageEntity = do props <- getNodePropList path hist <- getNodeHistory True path content <- getFileContentsLBS path let pageRev = fst $ head hist mimeType = read $ fromMaybe "text/x-rakka" $ fmap chomp (lookup "svn:mime-type" props) lastMod <- getRevisionProp "svn:date" >>= return . fromJust . parseW3CDateTime . chomp . fromJust return Entity { pageName = name , pageType = mimeType , pageLanguage = fmap chomp (lookup "rakka:lang" props) , pageFileName = fmap chomp (lookup "rakka:fileName" props) , pageIsTheme = any ((== "rakka:isTheme") . fst) props , pageIsFeed = any ((== "rakka:isFeed") . fst) props , pageIsLocked = any ((== "rakka:isLocked") . fst) props , pageIsBoring = any ((== "rakka:isBoring") . fst) props , pageIsBinary = case mimeType of MIMEType "text" _ _ -> any ((== "rakka:isBinary") . fst) props _ -> True , pageRevision = pageRev , pageLastMod = zonedTimeToUTC lastMod , pageSummary = lookup "rakka:summary" props , pageOtherLang = fromMaybe M.empty $ fmap (M.fromList . fromJust . deserializeStringPairs) (lookup "rakka:otherLang" props) , pageContent = content } loadPageRedirect :: Rev Page loadPageRedirect = fail "FIXME: loadPageRedirect: not implemented"