gdritter repos lektor / 1ecceeb
Finished Atom example Getty Ritter 8 years ago
4 changed file(s) with 34 addition(s) and 66 deletion(s). Collapse all Expand all
1414 main-is: Main.hs
1515 default-language: Haskell2010
1616 ghc-options: -Wall
17 build-depends: base >= 4 && < 5, feed, HTTP, SHA, xml, bytestring, directory, filepath, hostname, time, unix
17 build-depends: base >= 4 && < 5, feed, HTTP, SHA, xml, bytestring, directory, filepath, hostname, time, unix, random
1818
1919 source-repository head
2020 type: git
2727 , L.entryTitle = toString entryTitle
2828 , L.entryContent = maybe "" entryToString entryContent
2929 , L.entryAuthor = toPeople entryAuthors
30 , L.entryPubdate = undefined
31 , L.entryType = undefined
30 , L.entryPubdate = Just entryUpdated
31 , L.entryType = fmap entryToType entryContent
3232 }
3333
3434 toString :: TextContent -> String
4343 entryToString (MixedContent _ _) = "[unimplemented]"
4444 entryToString (ExternalContent _ _) = "[unimplemented]"
4545
46 entryToType :: EntryContent -> String
47 entryToType HTMLContent {} = "text/html"
48 entryToType XHTMLContent {} = "text/xhtml"
49 entryToType _ = "text/plain"
50
4651 toPeople :: [Person] -> Maybe String
4752 toPeople [] = Nothing
4853 toPeople xs = Just (unlines (map toPerson xs))
11 {-# LANGUAGE RecordWildCards #-}
2 {-# LANGUAGE ScopedTypeVariables #-}
32
43 module Lektor
54 ( Feed(..)
65 , Entry(..)
76 , mkFeed
87 , mkEntry
8 , writeAll
99 , writeFeed
1010 , writeEntry
1111 ) where
2020 import System.FilePath ((</>))
2121 import System.Posix.Files (createSymbolicLink)
2222 import System.Posix.Process (getProcessID)
23 import System.Random (randomIO)
2324
2425 mkdirP :: FilePath -> IO ()
2526 mkdirP = createDirectoryIfMissing True
5758 mkEntry entryId entryTitle entryContent =
5859 Entry entryId entryTitle entryContent Nothing Nothing Nothing
5960
61 writeAll :: (Feed, [Entry]) -> IO ()
62 writeAll (feed, entries) = do
63 writeFeed feed
64 mapM_ (writeEntry feed) entries
65
6066 writeFeed :: Feed -> IO ()
6167 writeFeed Feed { .. } = do
6268 let dir = "src" </> hash feedId
6975 writeFileMb (dir </> "copyright") feedCopy
7076 writeFileMb (dir </> "author") feedAuthor
7177
72 writeEntry :: Entry -> Feed -> IO ()
73 writeEntry (Entry { .. }) (Feed { feedId = feedId }) = do
78 writeEntry :: Feed -> Entry -> IO ()
79 writeEntry (Feed { feedId = feedId }) (Entry { .. }) = do
7480 let feedHash = hash feedId
7581 uniq <- mkUniq
7682 let dir = "tmp" </> feedHash </> uniq
83 cwd <- getCurrentDirectory
7784 mkdirP dir
7885 mkdirP ("new" </> hash feedId)
7986 writeFile (dir </> "id") entryId
8289 writeFileMb (dir </> "author") entryAuthor
8390 writeFileMb (dir </> "pubdate") entryPubdate
8491 writeFileMb (dir </> "type") entryType
85 createSymbolicLink (dir </> "feed") ("src" </> feedHash)
92 createSymbolicLink (cwd </> "src" </> feedHash) (dir </> "feed")
8693 renameDirectory dir ("new" </> feedHash </> uniq)
94
95 integer :: Integer -> Integer
96 integer = id
8797
8898 mkUniq :: IO String
8999 mkUniq = do
90 (t :: Integer, r') <- properFraction `fmap` getPOSIXTime
91 let r = filter isDigit (show r')
92 let m = ""
100 (t, m') <- properFraction `fmap` getPOSIXTime
101 let m = filter isDigit (show m')
102 r <- abs `fmap` randomIO
93103 p <- getProcessID
94104 h <- getHostName
95 let uniq = "P" <> show p <> "R" <> r <> "M" <> m
96 return (show t <> "." <> uniq <> "." <> h)
105 let uniq = "P" <> show p <> "R" <> show (integer r) <> "M" <> m
106 return (show (integer t) <> "." <> uniq <> "." <> h)
55 module Main where
66
77 import qualified Lektor as L
8
98 import qualified Atom as A
109
11 import Control.Monad (zipWithM_)
12 import Data.ByteString.Lazy.Char8 (pack)
13 import Data.Digest.Pure.SHA
14 import Data.Monoid ((<>))
15 import Data.Time.Clock.POSIX (getPOSIXTime)
16 import Network.HostName
1710 import Network.HTTP
1811 import System.Directory
1912 import System.Environment
20 -- import System.Exit (die)
21 import System.FilePath ((</>))
22 import System.Posix.Process (getProcessID)
2313 import Text.Atom.Feed.Import (elementFeed)
24 import Text.Atom.Feed
2514 import Text.XML.Light.Input (parseXMLDoc)
2615
16 die :: String -> a
2717 die = error
2818
2919 usage :: String
4333 [] -> putStrLn usage
4434 (url:_) -> do
4535 simpleHTTP (getRequest url) >>= \case
46 Left err -> die "Unable to fetch document"
47 Right r -> makeEntries url (rspBody r)
36 Left _ -> die "Unable to fetch document"
37 Right r -> writeAsAtom (rspBody r)
4838
49 makeEntries :: String -> String -> IO ()
50 makeEntries url s = case parseXMLDoc s of
51 Nothing -> die "Unale to parse XML document"
39 writeAsAtom :: String -> IO ()
40 writeAsAtom s = case parseXMLDoc s of
41 Nothing -> die "Unable to parse XML document"
5242 Just xml -> case elementFeed xml of
53 Just atom -> buildLektorDir url atom
5443 Nothing -> die "XML document not an Atom feed"
55
56 contentAsString :: TextContent -> String
57 contentAsString (TextString s) = s
58 contentAsString _ = error "..."
59
60 buildLektorDir :: String -> Feed -> IO ()
61 buildLektorDir url feed = do
62 let hash = showDigest (sha1 (pack url))
63 mapM_ (createDirectoryIfMissing True)
64 [ "src" </> hash
65 , "tmp" </> hash
66 , "new" </> hash
67 , "cur" </> hash
68 ]
69 writeFile ("src" </> hash </> "name")
70 (contentAsString (feedTitle feed))
71 writeFile ("src" </> hash </> "id") url
72 zipWithM_ (buildLektorEntry hash) [0..] (reverse (feedEntries feed))
73
74 buildLektorEntry :: String -> Int -> Entry -> IO ()
75 buildLektorEntry hash n (Entry { .. }) = do
76 t <- fmap (floor . realToFrac) getPOSIXTime
77 p <- getProcessID
78 h <- getHostName
79 let dirId = show t <> ".P" <> show p <> "Q" <> show n <> "." <> h
80 let tmpDir = "tmp" </> hash </> dirId
81 createDirectoryIfMissing True tmpDir
82 writeFile (tmpDir </> "title") (contentAsString entryTitle)
83 writeFile (tmpDir </> "id") entryId
84 writeFile (tmpDir </> "content") $ case entryContent of
85 Just (TextContent s) -> s
86 Just (HTMLContent s) -> s
87 _ -> "[unsupported content]"
88 writeFile (tmpDir </> "type") $ case entryContent of
89 Just (HTMLContent s) -> "text/html"
90 _ -> "text/plain"
91 renameDirectory tmpDir ("new" </> hash </> dirId)
44 Just atom -> L.writeAll (A.atomToLektor atom)