epub-metadata 2.0.2 → 2.1.0
raw patch · 5 files changed
+42/−59 lines, 5 filesdep +bytestringdep +zip-archivedep −LibZipsetup-changedPVP ok
version bump matches the API change (PVP)
Dependencies added: bytestring, zip-archive
Dependencies removed: LibZip
API changes (from Hackage documentation)
- Codec.Epub.IO: extractFileFromZip :: (MonadIO m, MonadError String m) => FilePath -> FilePath -> m String
- Codec.Epub.IO: opfPath :: (MonadError String m, MonadIO m) => FilePath -> m String
+ Codec.Epub.IO: opfContents :: (MonadError String m, MonadIO m) => FilePath -> m String
Files
- Setup.hs +1/−21
- epub-metadata.cabal +4/−4
- src/Codec/Epub/IO.hs +33/−29
- src/Codec/Epub/Opf/Cli/Opts.hs +1/−1
- src/Codec/Epub/Opf/Parse.hs +3/−4
Setup.hs view
@@ -4,35 +4,15 @@ -- License: BSD3 (see LICENSE) -- Author: Dino Morelli <dino@ui3.info> -import Control.Monad ( unless ) import Distribution.Simple import System.Cmd ( system )-import System.Directory ( createDirectoryIfMissing )-import System.FilePath-import System.Posix.Files ( createSymbolicLink, fileExist ) main = defaultMainWithHooks (simpleUserHooks - { postBuild = customPostBuild- , runTests = testRunner+ { runTests = testRunner } ) where- -- Create symlink to the binary after build for developer - -- convenience- customPostBuild _ _ _ _ = do- let binDir = "bin"- let binName = "epubmeta"- let destPath = binDir </> binName-- createDirectoryIfMissing True binDir-- linkExists <- fileExist destPath- unless linkExists $ do- createSymbolicLink- (".." </> "dist" </> "build" </> binName </> binName)- destPath- -- Target for running all unit tests testRunner _ _ _ _ = do system $ "runhaskell -isrc testsuite/runtests.hs"
epub-metadata.cabal view
@@ -1,5 +1,5 @@ name: epub-metadata-version: 2.0.2+version: 2.1.0 cabal-version: >= 1.2 build-type: Simple license: BSD3@@ -17,7 +17,7 @@ utility to dump OPF package data to stdout in a human-readable form. category: Codec, Text-tested-with: GHC>=6.12.1+tested-with: GHC >= 6.12.3 library exposed-modules: Codec.Epub.IO,@@ -35,8 +35,8 @@ Codec.Epub.Opf.Package.Spine, Codec.Epub.Opf.Parse hs-source-dirs: src- build-depends: base >= 3 && < 5, containers, hxt >= 9, LibZip, - mtl, regex-compat+ build-depends: base >= 3 && < 5, bytestring, containers,+ hxt >= 9, mtl, regex-compat, zip-archive ghc-options: -Wall executable epubmeta
src/Codec/Epub/IO.hs view
@@ -5,17 +5,15 @@ {-# LANGUAGE FlexibleContexts #-} {- | Functions for doing some disk IO with ePub documents-- Note that these functions do their work by using the external - unzip utility. -} module Codec.Epub.IO- ( extractFileFromZip, opfPath )+ ( opfContents ) where -import Codec.Archive.LibZip+import Codec.Archive.Zip import Control.Arrow.ListArrows ( (>>>), deep ) import Control.Monad.Error+import qualified Data.ByteString.Lazy.Char8 as B import Text.Regex import Text.XML.HXT.Arrow.XmlArrow ( getAttrValue, hasName, isElem ) import Text.XML.HXT.Arrow.XmlState ( no, runX, withValidate )@@ -34,37 +32,43 @@ (mkRegexWithOpts "<!DOCTYPE [^>]*>" False True)) "" -{- | Extract a file from a zipfile.--}-extractFileFromZip :: (MonadIO m, MonadError String m)- => FilePath -- ^ path to zip file- -> FilePath -- ^ path within zip file to extract- -> m String -- ^ contents of expected file-extractFileFromZip zipPath filePath = do- result <- liftIO $ catchZipError- (fmap Right $ withArchive [] zipPath $ fileContents [] filePath)- (return . Left)-- output <- either (throwError . show) return result-- return . removeEncoding . removeDoctype $ output+-- | Extract a file from a zip archive throwing an error on failure+fileFromArchive :: MonadError String m =>+ FilePath -> Archive -> m String+fileFromArchive filePath archive = do+ let mbEntry = findEntryByPath filePath archive+ maybe+ (throwError $ "Unable to locate file " ++ filePath)+ (return . B.unpack . fromEntry) mbEntry --- | Get the path within an ePub file to the OPF Package Document-opfPath :: (MonadError String m, MonadIO m)+-- | Get the contents of the OPF Package Document from an ePub file+opfContents :: (MonadError String m, MonadIO m) => FilePath -- ^ path to ePub zip file- -> m String -- ^ path within ePub to the OPF Package Document-opfPath zipPath = do- containerContents <- extractFileFromZip zipPath- "META-INF/container.xml"+ -> m String -- ^ contents of the OPF Package Document+opfContents zipPath = do+ {- We need to first extract the container.xml file+ It's required to have a certain path and name in the epub+ and contains the path to what we really want, the .opf file.+ -}+ zipFileBytes <- liftIO $ B.readFile zipPath+ let archive = toArchive zipFileBytes + let containerPath = "META-INF/container.xml"+ containerDoc <- fileFromArchive containerPath archive+ result <- liftIO $ runX (- readString [withValidate no] containerContents+ readString [withValidate no] containerDoc >>> deep (isElem >>> hasName "rootfile") >>> getAttrValue "full-path" ) - case result of+ rootPath <- case result of (p : []) -> return p- _ -> throwError- "ERROR: rootfile full-path missing from META-INF/container.xml"+ _ -> throwError $+ "ERROR: rootfile full-path missing from " ++ containerPath++ -- Now that we have the path to the .opf file, extract it+ rootDoc <- fileFromArchive rootPath archive++ return . removeEncoding . removeDoctype $ rootDoc
src/Codec/Epub/Opf/Cli/Opts.hs view
@@ -52,5 +52,5 @@ , "Options:" ] footer = init $ unlines- [ "Version 2.0.2 Dino Morelli <dino@ui3.info>"+ [ "Version 2.1.0 Dino Morelli <dino@ui3.info>" ]
src/Codec/Epub/Opf/Parse.hs view
@@ -251,9 +251,9 @@ XML string -} parseXmlToOpf :: (MonadIO m) => String -> m [Package]-parseXmlToOpf opfContents =+parseXmlToOpf contents = liftIO $ runX (- readString [withValidate no] opfContents+ readString [withValidate no] contents >>> propagateNamespaces >>> getBookData )@@ -263,8 +263,7 @@ parseEpubOpf :: (MonadIO m, MonadError String m) => FilePath -> m Package parseEpubOpf zipPath = do- opfContents <- extractFileFromZip zipPath =<< opfPath zipPath- result <- parseXmlToOpf opfContents+ result <- opfContents zipPath >>= parseXmlToOpf case result of (em : []) -> return em