Data files changes.

* Added `embed_data_files` flag.  (not yet used)
* Shared no longer exports `findDataFile`.
* `readDataFile` now returns a strict bytestring.
* Shared now exports `readDataFileUTF8` which returns a string like
  the old `readDataFile`.
* Rewrote modules to use new data file functions and to avoid
  using functions from Paths_pandoc directly.
This commit is contained in:
John MacFarlane 2012-12-29 17:44:02 -08:00
parent 32c5a8e2dc
commit 1864bb0994
9 changed files with 64 additions and 67 deletions

View file

@ -1,5 +1,5 @@
import Text.Pandoc import Text.Pandoc
import Text.Pandoc.Shared (readDataFile, normalize) import Text.Pandoc.Shared (readDataFileUTF8, normalize)
import Criterion.Main import Criterion.Main
import Criterion.Config import Criterion.Config
import Text.JSON.Generic import Text.JSON.Generic
@ -35,8 +35,8 @@ main :: IO ()
main = do main = do
args <- getArgs args <- getArgs
(conf,_) <- parseArgs defaultConfig{ cfgSamples = Last $ Just 20 } defaultOptions args (conf,_) <- parseArgs defaultConfig{ cfgSamples = Last $ Just 20 } defaultOptions args
inp <- readDataFile (Just ".") "README" inp <- readDataFileUTF8 (Just ".") "README"
inp2 <- readDataFile (Just ".") "tests/testsuite.txt" inp2 <- readDataFileUTF8 (Just ".") "tests/testsuite.txt"
let opts = def{ readerSmart = True } let opts = def{ readerSmart = True }
let doc = readMarkdown opts $ inp ++ unlines (drop 3 $ lines inp2) let doc = readMarkdown opts $ inp ++ unlines (drop 3 $ lines inp2)
let readerBs = map (readerBench doc) readers let readerBs = map (readerBench doc) readers

View file

@ -187,6 +187,9 @@ Source-repository head
Flag blaze_html_0_5 Flag blaze_html_0_5
Description: Use blaze-html 0.5 and blaze-markup 0.5 Description: Use blaze-html 0.5 and blaze-markup 0.5
Default: True Default: True
Flag embed_data_files
Description: Embed data files in binary for relocatable executable.
Default: False
Library Library
Build-Depends: base >= 4.2 && <5, Build-Depends: base >= 4.2 && <5,
@ -224,6 +227,10 @@ Library
else else
build-depends: build-depends:
blaze-html >= 0.4.3.0 && < 0.5 blaze-html >= 0.4.3.0 && < 0.5
if flag(embed_data_files)
build-depends: file-embed >= 0.0.4 && < 0.1,
template-haskell >= 2.4 && < 2.9
cpp-options: -DEMBED_DATA_FILES
if impl(ghc >= 7.0.1) if impl(ghc >= 7.0.1)
Ghc-Options: -O2 -rtsopts -Wall -fno-warn-unused-do-bind -dno-debug-output Ghc-Options: -O2 -rtsopts -Wall -fno-warn-unused-do-bind -dno-debug-output
else else

View file

@ -33,7 +33,7 @@ module Main where
import Text.Pandoc import Text.Pandoc
import Text.Pandoc.PDF (tex2pdf) import Text.Pandoc.PDF (tex2pdf)
import Text.Pandoc.Readers.LaTeX (handleIncludes) import Text.Pandoc.Readers.LaTeX (handleIncludes)
import Text.Pandoc.Shared ( tabFilter, readDataFile, safeRead, import Text.Pandoc.Shared ( tabFilter, readDataFileUTF8, safeRead,
headerShift, normalize, err, warn ) headerShift, normalize, err, warn )
import Text.Pandoc.XML ( toEntities, fromEntities ) import Text.Pandoc.XML ( toEntities, fromEntities )
import Text.Pandoc.SelfContained ( makeSelfContained ) import Text.Pandoc.SelfContained ( makeSelfContained )
@ -889,24 +889,27 @@ main = do
E.catch (UTF8.readFile tp') E.catch (UTF8.readFile tp')
(\e -> if isDoesNotExistError e (\e -> if isDoesNotExistError e
then E.catch then E.catch
(readDataFile datadir $ (readDataFileUTF8 datadir
"templates" </> tp') ("templates" </> tp'))
(\e' -> let _ = (e' :: E.SomeException) (\e' -> let _ = (e' :: E.SomeException)
in throwIO e') in throwIO e')
else throwIO e) else throwIO e)
variables' <- case mathMethod of variables' <- case mathMethod of
LaTeXMathML Nothing -> do LaTeXMathML Nothing -> do
s <- readDataFile datadir $ "data" </> "LaTeXMathML.js" s <- readDataFileUTF8 datadir
("data" </> "LaTeXMathML.js")
return $ ("mathml-script", s) : variables return $ ("mathml-script", s) : variables
MathML Nothing -> do MathML Nothing -> do
s <- readDataFile datadir $ "data"</>"MathMLinHTML.js" s <- readDataFileUTF8 datadir
("data"</>"MathMLinHTML.js")
return $ ("mathml-script", s) : variables return $ ("mathml-script", s) : variables
_ -> return variables _ -> return variables
variables'' <- if "dzslides" `isPrefixOf` writerName' variables'' <- if "dzslides" `isPrefixOf` writerName'
then do then do
dztempl <- readDataFile datadir $ "dzslides" </> "template.html" dztempl <- readDataFileUTF8 datadir
("dzslides" </> "template.html")
let dzcore = unlines $ dropWhile (not . isPrefixOf "<!-- {{{{ dzslides core") let dzcore = unlines $ dropWhile (not . isPrefixOf "<!-- {{{{ dzslides core")
$ lines dztempl $ lines dztempl
return $ ("dzslides-core", dzcore) : variables' return $ ("dzslides-core", dzcore) : variables'
@ -927,15 +930,16 @@ main = do
then do then do
csl <- CSL.parseCSL =<< csl <- CSL.parseCSL =<<
case mbCsl of case mbCsl of
Nothing -> readDataFile datadir "default.csl" Nothing -> readDataFileUTF8 datadir
"default.csl"
Just cslfile -> do Just cslfile -> do
exists <- doesFileExist cslfile exists <- doesFileExist cslfile
if exists if exists
then UTF8.readFile cslfile then UTF8.readFile cslfile
else do else do
csldir <- getAppUserDataDirectory "csl" csldir <- getAppUserDataDirectory "csl"
readDataFile (Just csldir) readDataFileUTF8 (Just csldir)
(replaceExtension cslfile "csl") (replaceExtension cslfile "csl")
abbrevs <- maybe (return []) CSL.readJsonAbbrevFile cslabbrevs abbrevs <- maybe (return []) CSL.readJsonAbbrevFile cslabbrevs
return $ Just csl { CSL.styleAbbrevs = abbrevs } return $ Just csl { CSL.styleAbbrevs = abbrevs }
else return Nothing else return Nothing

View file

@ -41,7 +41,7 @@ import System.FilePath (takeExtension, dropExtension, takeDirectory, (</>))
import Data.Char (toLower, isAscii, isAlphaNum) import Data.Char (toLower, isAscii, isAlphaNum)
import Codec.Compression.GZip as Gzip import Codec.Compression.GZip as Gzip
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy as L
import Text.Pandoc.Shared (findDataFile, renderTags') import Text.Pandoc.Shared (readDataFile, renderTags')
import Text.Pandoc.MIME (getMimeType) import Text.Pandoc.MIME (getMimeType)
import System.Directory (doesFileExist) import System.Directory (doesFileExist)
import Text.Pandoc.UTF8 (toString, fromString) import Text.Pandoc.UTF8 (toString, fromString)
@ -55,18 +55,8 @@ getItem userdata f =
".gz" -> getMimeType $ dropExtension f ".gz" -> getMimeType $ dropExtension f
x -> getMimeType x x -> getMimeType x
exists <- doesFileExist f exists <- doesFileExist f
if exists cont <- if exists then B.readFile f else readDataFile userdata f
then do return (cont, mime)
cont <- B.readFile f
return (cont, mime)
else do
res <- findDataFile userdata f
exists' <- doesFileExist res
if exists'
then do
cont <- B.readFile res
return (cont, mime)
else error $ "Could not find `" ++ f ++ "'"
-- TODO - have this return mime type too - then it can work for google -- TODO - have this return mime type too - then it can work for google
-- chart API, e.g. -- chart API, e.g.

View file

@ -1,4 +1,4 @@
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable, CPP #-}
{- {-
Copyright (C) 2006-2010 John MacFarlane <jgm@berkeley.edu> Copyright (C) 2006-2010 John MacFarlane <jgm@berkeley.edu>
@ -64,8 +64,8 @@ module Text.Pandoc.Shared (
renderTags', renderTags',
-- * File handling -- * File handling
inDirectory, inDirectory,
findDataFile,
readDataFile, readDataFile,
readDataFileUTF8,
-- * Error handling -- * Error handling
err, err,
warn, warn,
@ -89,13 +89,18 @@ import System.FilePath ( (</>) )
import Data.Generics (Typeable, Data) import Data.Generics (Typeable, Data)
import qualified Control.Monad.State as S import qualified Control.Monad.State as S
import Control.Monad (msum) import Control.Monad (msum)
import Paths_pandoc (getDataFileName)
import Text.Pandoc.Pretty (charWidth) import Text.Pandoc.Pretty (charWidth)
import System.Locale (defaultTimeLocale) import System.Locale (defaultTimeLocale)
import Data.Time import Data.Time
import System.IO (stderr) import System.IO (stderr)
import Text.HTML.TagSoup (renderTagsOptions, RenderOptions(..), Tag(..), import Text.HTML.TagSoup (renderTagsOptions, RenderOptions(..), Tag(..),
renderOptions) renderOptions)
import qualified Data.ByteString as B
#ifdef EMBED_DATA_FILES
import Data.FileEmbed
#else
import Paths_pandoc (getDataFileName)
#endif
-- --
-- List processing -- List processing
@ -499,20 +504,28 @@ inDirectory path action = do
setCurrentDirectory oldDir setCurrentDirectory oldDir
return result return result
-- | Get file path for data file, either from specified user data directory, readDefaultDataFile :: FilePath -> IO B.ByteString
-- or, if not found there, from Cabal data directory. readDefaultDataFile fname =
findDataFile :: Maybe FilePath -> FilePath -> IO FilePath #ifdef EMBED_DATA_FILES
findDataFile Nothing f = getDataFileName f TODO
findDataFile (Just u) f = do #else
ex <- doesFileExist (u </> f) getDataFileName fname >>= B.readFile
if ex #endif
then return (u </> f)
else getDataFileName f
-- | Read file from specified user data directory or, if not found there, from -- | Read file from specified user data directory or, if not found there, from
-- Cabal data directory. -- Cabal data directory.
readDataFile :: Maybe FilePath -> FilePath -> IO String readDataFile :: Maybe FilePath -> FilePath -> IO B.ByteString
readDataFile userDir fname = findDataFile userDir fname >>= UTF8.readFile readDataFile Nothing fname = readDefaultDataFile fname
readDataFile (Just userDir) fname = do
exists <- doesFileExist (userDir </> fname)
if exists
then B.readFile (userDir </> fname)
else readDefaultDataFile fname
-- | Same as 'readDataFile' but returns a String instead of a ByteString.
readDataFileUTF8 :: Maybe FilePath -> FilePath -> IO String
readDataFileUTF8 userDir fname =
UTF8.toString `fmap` readDataFile userDir fname
-- --
-- Error reporting -- Error reporting

View file

@ -80,7 +80,7 @@ import Text.Blaze (preEscapedString, Html)
#endif #endif
import Text.Pandoc.UTF8 (fromStringLazy) import Text.Pandoc.UTF8 (fromStringLazy)
import Data.ByteString.Lazy (ByteString) import Data.ByteString.Lazy (ByteString)
import Text.Pandoc.Shared (readDataFile) import Text.Pandoc.Shared (readDataFileUTF8)
import qualified Control.Exception.Extensible as E (try, IOException) import qualified Control.Exception.Extensible as E (try, IOException)
-- | Get default template for the specified writer. -- | Get default template for the specified writer.
@ -98,7 +98,7 @@ getDefaultTemplate user writer = do
"multimarkdown" -> getDefaultTemplate user "markdown" "multimarkdown" -> getDefaultTemplate user "markdown"
"markdown_github" -> getDefaultTemplate user "markdown" "markdown_github" -> getDefaultTemplate user "markdown"
_ -> let fname = "templates" </> "default" <.> format _ -> let fname = "templates" </> "default" <.> format
in E.try $ readDataFile user fname in E.try $ readDataFileUTF8 user fname
data TemplateState = TemplateState Int [(String,String)] data TemplateState = TemplateState Int [(String,String)]

View file

@ -29,14 +29,12 @@ Conversion of 'Pandoc' documents to docx.
-} -}
module Text.Pandoc.Writers.Docx ( writeDocx ) where module Text.Pandoc.Writers.Docx ( writeDocx ) where
import Data.List ( intercalate ) import Data.List ( intercalate )
import System.FilePath ( (</>) )
import qualified Data.ByteString.Lazy as B import qualified Data.ByteString.Lazy as B
import qualified Data.Map as M import qualified Data.Map as M
import qualified Text.Pandoc.UTF8 as UTF8 import qualified Text.Pandoc.UTF8 as UTF8
import System.IO ( stderr ) import System.IO ( stderr )
import Codec.Archive.Zip import Codec.Archive.Zip
import Data.Time.Clock.POSIX import Data.Time.Clock.POSIX
import Paths_pandoc ( getDataFileName )
import Text.Pandoc.Definition import Text.Pandoc.Definition
import Text.Pandoc.Generic import Text.Pandoc.Generic
import System.Directory import System.Directory
@ -104,15 +102,8 @@ writeDocx opts doc@(Pandoc (Meta tit auths date) _) = do
refArchive <- liftM toArchive $ refArchive <- liftM toArchive $
case writerReferenceDocx opts of case writerReferenceDocx opts of
Just f -> B.readFile f Just f -> B.readFile f
Nothing -> do Nothing -> (B.fromChunks . (:[])) `fmap`
let defaultDocx = getDataFileName "reference.docx" >>= B.readFile readDataFile datadir "reference.docx"
case datadir of
Nothing -> defaultDocx
Just d -> do
exists <- doesFileExist (d </> "reference.docx")
if exists
then B.readFile (d </> "reference.docx")
else defaultDocx
(newContents, st) <- runStateT (writeOpenXML opts{writerWrapText = False} doc) (newContents, st) <- runStateT (writeOpenXML opts{writerWrapText = False} doc)
defaultWriterState defaultWriterState

View file

@ -30,13 +30,13 @@ Conversion of 'Pandoc' documents to EPUB.
module Text.Pandoc.Writers.EPUB ( writeEPUB2, writeEPUB3 ) where module Text.Pandoc.Writers.EPUB ( writeEPUB2, writeEPUB3 ) where
import Data.IORef import Data.IORef
import Data.Maybe ( fromMaybe, isNothing ) import Data.Maybe ( fromMaybe, isNothing )
import Data.List ( isPrefixOf, isInfixOf, intercalate ) import Data.List ( isInfixOf, intercalate )
import System.Environment ( getEnv ) import System.Environment ( getEnv )
import Text.Printf (printf) import Text.Printf (printf)
import System.FilePath ( (</>), takeBaseName, takeExtension, takeFileName ) import System.FilePath ( (</>), takeBaseName, takeExtension, takeFileName )
import qualified Data.ByteString.Lazy as B import qualified Data.ByteString.Lazy as B
import qualified Data.ByteString.Lazy.Char8 as B8 import qualified Data.ByteString.Lazy.Char8 as B8
import Text.Pandoc.UTF8 ( fromStringLazy ) import Text.Pandoc.UTF8 ( fromStringLazy, toString )
import Codec.Archive.Zip import Codec.Archive.Zip
import Data.Time.Clock.POSIX import Data.Time.Clock.POSIX
import Data.Time import Data.Time
@ -321,7 +321,8 @@ writeEPUB version opts doc@(Pandoc meta _) = do
-- stylesheet -- stylesheet
stylesheet <- case writerEpubStylesheet opts of stylesheet <- case writerEpubStylesheet opts of
Just s -> return s Just s -> return s
Nothing -> readDataFile (writerUserDataDir opts) "epub.css" Nothing -> toString `fmap`
readDataFile (writerUserDataDir opts) "epub.css"
let stylesheetEntry = mkEntry "stylesheet.css" $ fromStringLazy stylesheet let stylesheetEntry = mkEntry "stylesheet.css" $ fromStringLazy stylesheet
-- construct archive -- construct archive

View file

@ -35,15 +35,13 @@ import qualified Data.ByteString.Lazy as B
import Text.Pandoc.UTF8 ( fromStringLazy ) import Text.Pandoc.UTF8 ( fromStringLazy )
import Codec.Archive.Zip import Codec.Archive.Zip
import Data.Time.Clock.POSIX import Data.Time.Clock.POSIX
import Paths_pandoc ( getDataFileName )
import Text.Pandoc.Options ( WriterOptions(..) ) import Text.Pandoc.Options ( WriterOptions(..) )
import Text.Pandoc.Shared ( stringify ) import Text.Pandoc.Shared ( stringify, readDataFile )
import Text.Pandoc.ImageSize ( readImageSize, sizeInPoints ) import Text.Pandoc.ImageSize ( readImageSize, sizeInPoints )
import Text.Pandoc.MIME ( getMimeType ) import Text.Pandoc.MIME ( getMimeType )
import Text.Pandoc.Definition import Text.Pandoc.Definition
import Text.Pandoc.Generic import Text.Pandoc.Generic
import Text.Pandoc.Writers.OpenDocument ( writeOpenDocument ) import Text.Pandoc.Writers.OpenDocument ( writeOpenDocument )
import System.Directory
import Control.Monad (liftM) import Control.Monad (liftM)
import Network.URI ( unEscapeString ) import Network.URI ( unEscapeString )
import Text.Pandoc.XML import Text.Pandoc.XML
@ -59,15 +57,8 @@ writeODT opts doc@(Pandoc (Meta title _ _) _) = do
refArchive <- liftM toArchive $ refArchive <- liftM toArchive $
case writerReferenceODT opts of case writerReferenceODT opts of
Just f -> B.readFile f Just f -> B.readFile f
Nothing -> do Nothing -> (B.fromChunks . (:[])) `fmap`
let defaultODT = getDataFileName "reference.odt" >>= B.readFile readDataFile datadir "reference.odt"
case datadir of
Nothing -> defaultODT
Just d -> do
exists <- doesFileExist (d </> "reference.odt")
if exists
then B.readFile (d </> "reference.odt")
else defaultODT
-- handle pictures -- handle pictures
picEntriesRef <- newIORef ([] :: [Entry]) picEntriesRef <- newIORef ([] :: [Entry])
let sourceDir = writerSourceDirectory opts let sourceDir = writerSourceDirectory opts