X-Git-Url: http://git.cielonegro.org/gitweb.cgi?a=blobdiff_plain;f=Rakka%2FStorage%2FDefaultPage.hs;h=8e79a6dbc9470062677d8a2a1a64e2d8e9aa930c;hb=e2fd35989e9765281523fd4ce05dcd0199bdbbad;hp=30b5fcf5f1c918d963052b57cd8db293adcf7bb8;hpb=f4a655a34bc6017db008c2e915053958ae13ee81;p=Rakka.git diff --git a/Rakka/Storage/DefaultPage.hs b/Rakka/Storage/DefaultPage.hs index 30b5fcf..8e79a6d 100644 --- a/Rakka/Storage/DefaultPage.hs +++ b/Rakka/Storage/DefaultPage.hs @@ -1,21 +1,27 @@ module Rakka.Storage.DefaultPage - ( loadDefaultPage + ( findAllDefaultPages + , loadDefaultPage ) where import qualified Codec.Binary.Base64 as B64 +import Codec.Binary.UTF8.String import Control.Arrow import Control.Arrow.ArrowIO import Control.Arrow.ArrowList import qualified Data.ByteString.Lazy as L -import Data.Encoding -import Data.Encoding.UTF8 import qualified Data.Map as M +import Data.Set (Set) +import qualified Data.Set as S +import Data.Time +import Data.Time.Clock.POSIX import Paths_Rakka -- Cabal が用意する。 import Rakka.Page import Rakka.Utils import System.Directory -import System.Time +import System.FilePath +import System.FilePath.Find hiding (fileName, modificationTime) +import System.Posix.Files import Text.XML.HXT.Arrow.ReadDocument import Text.XML.HXT.Arrow.XmlArrow import Text.XML.HXT.Arrow.XmlIOStateArrow @@ -24,20 +30,47 @@ import Text.XML.HXT.DOM.TypeDefs import Text.XML.HXT.DOM.XmlKeywords +doesLocalDirExist :: IO Bool +doesLocalDirExist = doesDirectoryExist "defaultPages" + + +findAllDefaultPages :: IO (Set PageName) +findAllDefaultPages + -- ./defaultPages が存在するなら、その中を探す。無ければ Cabal で + -- defaultPages を探す。 + = do localDirExists <- doesLocalDirExist + if localDirExists then + findAllIn "defaultPages" + else + -- FIXME: この getDataFileName の使ひ方は undocumented + findAllIn =<< getDataFileName "defaultPages" + where + findAllIn :: FilePath -> IO (Set PageName) + findAllIn dirPath + = find always (fileType ==? RegularFile) dirPath + >>= + return . S.fromList . map (decodePageName . makeRelative dirPath) + + loadDefaultPage :: PageName -> IO (Maybe Page) -loadDefaultPage pageName - -- ./defaultPages/Foo を探した後、Cabal で defaultPages/Foo を探す。 - = do let pagePath = "defaultPages/" ++ encodePageName pageName - isInDataDir <- doesFileExist pagePath - if isInDataDir then - return . Just =<< loadPageFile pageName pagePath +loadDefaultPage name + -- ./defaultPages が存在するなら、./defaultPages/Foo を探す。無けれ + -- ば Cabal で defaultPages/Foo を探す。 + = do let pagePath = "defaultPages" encodePageName name + + localDirExists <- doesLocalDirExist + if localDirExists then + tryLoad pagePath else - do fpath <- getDataFileName pagePath - isInstalled <- doesFileExist fpath - if isInstalled then - return . Just =<< loadPageFile pageName fpath - else - return Nothing + tryLoad =<< getDataFileName pagePath + where + tryLoad :: FilePath -> IO (Maybe Page) + tryLoad fpath + = do exists <- doesFileExist fpath + if exists then + return . Just =<< loadPageFile name fpath + else + return Nothing loadPageFile :: PageName -> FilePath -> IO Page @@ -58,11 +91,14 @@ loadPageFileA , (a_check_namespaces , v_1) , (a_remove_whitespace, v_1) ] -< fpath - lastMod <- arrIO (\ x -> getModificationTime x >>= toCalendarTime) -< fpath + lastMod <- arrIO (\ x -> getFileStatus x + >>= + return . posixSecondsToUTCTime . fromRational . toRational . modificationTime) + -< fpath parsePage -< (name, lastMod, tree) -parsePage :: (ArrowXml a, ArrowChoice a) => a (PageName, CalendarTime, XmlTree) Page +parsePage :: (ArrowXml a, ArrowChoice a) => a (PageName, UTCTime, XmlTree) Page parsePage = proc (name, lastMod, tree) -> do redirect <- maybeA (getXPathTreesInDoc "/page/@redirect/text()" >>> getText) -< tree @@ -76,13 +112,14 @@ parsePage }) -parseEntity :: (ArrowXml a, ArrowChoice a) => a (PageName, CalendarTime, XmlTree) Page +parseEntity :: (ArrowXml a, ArrowChoice a) => a (PageName, UTCTime, XmlTree) Page parseEntity = proc (name, lastMod, tree) -> do mimeType <- (getXPathTreesInDoc "/page/@type/text()" >>> getText >>> arr read) -< tree - lang <- maybeA (getXPathTreesInDoc "/page/@lang/text()" >>> getText) -< tree + lang <- maybeA (getXPathTreesInDoc "/page/@lang/text()" >>> getText) -< tree + fileName <- maybeA (getXPathTreesInDoc "/page/@filename/text()" >>> getText) -< tree isTheme <- (withDefault (getXPathTreesInDoc "/page/@isTheme/text()" >>> getText) "no" >>> parseYesOrNo) -< tree @@ -108,19 +145,21 @@ parseEntity let (isBinary, content) = case (textData, binaryData) of - (Just text, _ ) -> (False, encodeLazy UTF8 text ) - (_ , Just binary) -> (True , L.pack $ B64.decode binary) + (Just text, Nothing ) -> (False, L.pack $ encode text ) + (Nothing , Just binary) -> (True , L.pack $ B64.decode binary) + _ -> error "one of textData or binaryData is required" returnA -< Entity { pageName = name , pageType = mimeType , pageLanguage = lang + , pageFileName = fileName , pageIsTheme = isTheme , pageIsFeed = isFeed , pageIsLocked = isLocked , pageIsBoring = isBoring , pageIsBinary = isBinary - , pageRevision = Nothing + , pageRevision = 0 , pageLastMod = lastMod , pageSummary = summary , pageOtherLang = M.fromList otherLang