file-embed-lzma 0.0.1 → 0.1
raw patch · 5 files changed
+193/−76 lines, 5 filesdep ~basedep ~bytestringdep ~directoryPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base, bytestring, directory, filepath, lzma, template-haskell, text, transformers
API changes (from Hackage documentation)
+ FileEmbedLzma.Untyped: embedByteString :: FilePath -> Q Exp
+ FileEmbedLzma.Untyped: embedDir :: FilePath -> Q Exp
+ FileEmbedLzma.Untyped: embedLazyByteString :: FilePath -> Q Exp
+ FileEmbedLzma.Untyped: embedLazyText :: FilePath -> Q Exp
+ FileEmbedLzma.Untyped: embedRecursiveDir :: FilePath -> Q Exp
+ FileEmbedLzma.Untyped: embedText :: FilePath -> Q Exp
+ FileEmbedLzma.Untyped: lazyBytestringE :: ByteString -> Q Exp
+ FileEmbedLzma.Untyped: listDirectoryFiles :: FilePath -> IO [(FilePath, ByteString)]
+ FileEmbedLzma.Untyped: listDirectoryFilesF :: (FilePath -> IO [(FilePath, ByteString)]) -> FilePath -> IO [(FilePath, ByteString)]
+ FileEmbedLzma.Untyped: listRecursiveDirectoryFiles :: FilePath -> IO [(FilePath, ByteString)]
- FileEmbedLzma: embedByteString :: FilePath -> Q Exp
+ FileEmbedLzma: embedByteString :: FilePath -> Code Q ByteString
- FileEmbedLzma: embedDir :: FilePath -> Q Exp
+ FileEmbedLzma: embedDir :: FilePath -> Code Q [(FilePath, ByteString)]
- FileEmbedLzma: embedLazyByteString :: FilePath -> Q Exp
+ FileEmbedLzma: embedLazyByteString :: FilePath -> Code Q ByteString
- FileEmbedLzma: embedLazyText :: FilePath -> Q Exp
+ FileEmbedLzma: embedLazyText :: FilePath -> Code Q Text
- FileEmbedLzma: embedRecursiveDir :: FilePath -> Q Exp
+ FileEmbedLzma: embedRecursiveDir :: FilePath -> Code Q [(FilePath, ByteString)]
- FileEmbedLzma: embedText :: FilePath -> Q Exp
+ FileEmbedLzma: embedText :: FilePath -> Code Q Text
- FileEmbedLzma: lazyBytestringE :: ByteString -> Q Exp
+ FileEmbedLzma: lazyBytestringE :: ByteString -> Code Q ByteString
Files
- ChangeLog.md +6/−0
- example/Example.hs +2/−2
- file-embed-lzma.cabal +18/−19
- src/FileEmbedLzma.hs +54/−55
- src/FileEmbedLzma/Untyped.hs +113/−0
ChangeLog.md view
@@ -1,5 +1,11 @@ # Revision history for file-embed-lzma +## 0.1++- The default interface uses TTH (`Code`),+ the previous untyped TH interface is in the `FileEmbedLzma.Untyped` module.+- Support GHC-9.0.2...9.10.1+ ## 0.0.1 - Use `bytesPrimL` when available
example/Example.hs view
@@ -9,6 +9,6 @@ main :: IO () main = do- BS.putStr $(embedByteString "example/example.txt")- for_ $(embedRecursiveDir "example") $ \(n, bs) ->+ BS.putStr $$(embedByteString "example/example.txt")+ for_ $$(embedRecursiveDir "example") $ \(n, bs) -> print (n, BS.length bs)
file-embed-lzma.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.0 name: file-embed-lzma-version: 0.0.1+version: 0.1 synopsis: Use Template Haskell to embed (LZMA compressed) data. description: The @file-embed@ package let's embed file and dir contents.@@ -24,35 +24,34 @@ example/example.txt tested-with:- GHC ==8.0.2- || ==8.2.2- || ==8.4.4- || ==8.6.5- || ==8.8.4- || ==8.10.7- || ==9.0.2- || ==9.2.4- || ==9.4.1+ GHC ==9.0.2+ || ==9.2.8+ || ==9.4.8+ || ==9.6.6+ || ==9.8.2+ || ==9.10.1 source-repository head type: git location: https://github.com/phadej/file-embed-lzma.git library- exposed-modules: FileEmbedLzma+ exposed-modules:+ FileEmbedLzma+ FileEmbedLzma.Untyped -- GHC boot libraries build-depends:- base >=4.9.1.0 && <4.18- , bytestring ^>=0.10.8.1 || ^>=0.11.1.0- , directory ^>=1.3.0.0- , filepath >=1.1.4.1 && <1.5- , template-haskell >=2.11.1.0 && <2.20- , text ^>=1.2.3.0 || ^>=2.0- , transformers ^>=0.5.2.0+ base >=4.15.1.0 && <4.21+ , bytestring ^>=0.10.12.1 || ^>=0.11.1.0 || ^>=0.12.0.0+ , directory ^>=1.3.3.0+ , filepath ^>=1.4.2.1 || ^>=1.5.2.0+ , template-haskell >=2.17.0.0 && <2.23+ , text ^>=1.2.5.0 || ^>=2.0 || ^>=2.1+ , transformers ^>=0.5.6.2 || ^>=0.6.1.0 -- non bundled dependencies- build-depends: lzma ^>=0.0.0.4+ build-depends: lzma ^>=0.0.1.1 other-extensions: CPP OverloadedStrings
src/FileEmbedLzma.hs view
@@ -48,11 +48,9 @@ import qualified Data.Text.Lazy as LT import qualified Data.Text.Lazy.Encoding as LTE -#if MIN_VERSION_template_haskell(2,16,0) import qualified Data.ByteString.Internal as BS.Internal -import Language.Haskell.TH.Syntax (Bytes (..))-#endif+import Language.Haskell.TH.Syntax (Bytes (..), liftTyped) -- $setup -- >>> :set -XTemplateHaskell -dppr-cols=9999@@ -88,18 +86,13 @@ -- | Makes lazy 'LBS.ByteString' expression. -- Embedded value is compressed with LZMA.-lazyBytestringE :: LBS.ByteString -> Q Exp+lazyBytestringE :: LBS.ByteString -> Code Q LBS.ByteString lazyBytestringE lbs =- [| LZMA.decompress . LBS.fromStrict . unsafePerformIO |] `appE`- ([| BS.Unsafe.unsafePackAddressLen |] `appE` l `appE` s)+ [|| LZMA.decompress (LBS.fromStrict (unsafePerformIO (BS.Unsafe.unsafePackAddressLen $$(liftTyped l) $$(unsafeCodeCoerce s)))) ||] where bs = LBS.toStrict $ LZMA.compressWith params lbs-#if MIN_VERSION_template_haskell(2,16,0) s = litE $ bytesPrimL $ bsToBytes bs-#else- s = litE $ stringPrimL $ BS.unpack bs-#endif- l = litE $ integerL $ fromIntegral $ BS.length bs+ l = BS.length bs params = LZMA.defaultCompressParams {- doesn't seem to affect much@@ -108,15 +101,12 @@ } -} -#if MIN_VERSION_template_haskell(2,16,0) bsToBytes :: BS.ByteString -> Bytes bsToBytes (BS.Internal.PS fptr off len) = Bytes fptr (fromIntegral off) (fromIntegral len)-#endif -makeEmbeddedEntry :: Name -> (FilePath, (Int64, Int64)) -> Q Exp-makeEmbeddedEntry name (path, (off, len)) = do- let y = [| LBS.toStrict . LBS.take len . LBS.drop off |] `appE` varE name- [| (,) path |] `appE` y+makeEmbeddedEntry :: Code Q LBS.ByteString -> (FilePath, (Int64, Int64)) -> Code Q (FilePath, BS.ByteString)+makeEmbeddedEntry name (path, (off, len)) =+ [|| (path, LBS.toStrict (LBS.take len (LBS.drop off $$name))) ||] concatEntries :: Traversable t => t LBS.ByteString -> (LBS.ByteString, t (Int64, Int64)) concatEntries xs = (bslEndo LBS.empty, ys)@@ -135,24 +125,14 @@ -- Directories ------------------------------------------------------------------------------- + -- | Embed a @[('FilePath', 'Data.ByteString.ByteString')]@ list, traversing given directory.-embedDir :: FilePath -> Q Exp-embedDir topdir = do+embedDir :: FilePath -> Code Q [(FilePath, BS.ByteString)]+embedDir topdir = joinCode $ do pairs' <- runIO $ listDirectoryFiles topdir for_ pairs' $ qAddDependentFile . fst let pairs = makeAllRelative topdir pairs'- embedPairs pairs--embedPairs :: [(FilePath, LBS.ByteString)] -> Q Exp-embedPairs pairs = do- -- we do a hop to only embed single big bytestring.- -- it's beneficial as lzma have more stuff to compress- let (bsl, Compose offsets) = concatEntries (Compose pairs)- bslName <- newName "embedBsl"- bslExpr <- lazyBytestringE bsl- let e = letE [ return $ ValD (VarP bslName) (NormalB bslExpr) [] ] $- listE $ map (makeEmbeddedEntry bslName) offsets- sigE e [t| [(FilePath, BS.ByteString)] |]+ return $ embedPairs pairs -- | Embed a @[('FilePath', 'Data.ByteString.ByteString')]@ list, recursively traversing given directory path. --@@ -165,60 +145,79 @@ -- @ -- ----- >>> $(embedRecursiveDir "example")+-- >>> $$(embedRecursiveDir "example") -- [("/Example.hs","..."),("/example.txt","Hello from the inside.\n")] ----- >>> :t $(embedRecursiveDir "example")--- $(embedRecursiveDir "example") :: [(FilePath, BS.ByteString)]+-- >>> :t $$(embedRecursiveDir "example")+-- $$(embedRecursiveDir "example") :: [(FilePath, BS.ByteString)] ---embedRecursiveDir :: FilePath -> Q Exp-embedRecursiveDir topdir = do+embedRecursiveDir :: FilePath -> Code Q [(FilePath, BS.ByteString)]+embedRecursiveDir topdir = joinCode $ do pairs' <- runIO $ listRecursiveDirectoryFiles topdir for_ pairs' $ qAddDependentFile . fst let pairs = sort (makeAllRelative topdir pairs')- embedPairs pairs+ return $ embedPairs pairs +embedPairs :: [(FilePath, LBS.ByteString)] -> Code Q [(FilePath, BS.ByteString)]+embedPairs pairs = do+ -- we do a hop to only embed single big bytestring.+ -- it's beneficial as lzma have more stuff to compress+ let (bsl, Compose offsets) = concatEntries (Compose pairs)+ let e = [|| let embedded = $$(lazyBytestringE bsl)+ in $$(typedListE (map (makeEmbeddedEntry [|| embedded ||]) offsets)) ||]+ typedSigE e [t| [(FilePath, BS.ByteString)] |]+ ------------------------------------------------------------------------------- -- Strings ------------------------------------------------------------------------------- -- | Embed a lazy 'Data.ByteString.Lazy.ByteString' from a file. ----- >>> :t $(embedLazyByteString "file-embed-lzma.cabal")--- $(embedLazyByteString "file-embed-lzma.cabal") :: LBS.ByteString+-- >>> :t $$(embedLazyByteString "file-embed-lzma.cabal")+-- $$(embedLazyByteString "file-embed-lzma.cabal") :: LBS.ByteString ---embedLazyByteString :: FilePath -> Q Exp-embedLazyByteString fp = do+embedLazyByteString :: FilePath -> Code Q LBS.ByteString+embedLazyByteString fp = joinCode $ do qAddDependentFile fp bsl <- runIO $ LBS.readFile fp- lazyBytestringE bsl+ return $ lazyBytestringE bsl -- | Embed a strict 'Data.ByteString.ByteString' from a file. ----- >>> :t $(embedByteString "file-embed-lzma.cabal")--- $(embedByteString "file-embed-lzma.cabal") :: BS.ByteString+-- >>> :t $$(embedByteString "file-embed-lzma.cabal")+-- $$(embedByteString "file-embed-lzma.cabal") :: BS...ByteString ---embedByteString :: FilePath -> Q Exp-embedByteString fp = [| LBS.toStrict |] `appE` embedLazyByteString fp+embedByteString :: FilePath -> Code Q BS.ByteString+embedByteString fp = [|| LBS.toStrict $$(embedLazyByteString fp) ||] -- | Embed a lazy 'Data.Text.Lazy.Text' from a UTF8-encoded file. ----- >>> :t $(embedLazyText "file-embed-lzma.cabal")--- $(embedLazyText "file-embed-lzma.cabal") :: LT.Text+-- >>> :t $$(embedLazyText "file-embed-lzma.cabal")+-- $$(embedLazyText "file-embed-lzma.cabal") :: LT.Text ---embedLazyText :: FilePath -> Q Exp-embedLazyText fp = do+embedLazyText :: FilePath -> Code Q LT.Text+embedLazyText fp = joinCode $ do qAddDependentFile fp bsl <- runIO $ LBS.readFile fp case LTE.decodeUtf8' bsl of Left e -> reportError (show e) Right _ -> return ()- [| LTE.decodeUtf8 |] `appE` lazyBytestringE bsl+ return $ [|| LTE.decodeUtf8 $$(lazyBytestringE bsl) ||] -- | Embed a strict 'Data.Text.Text' from a UTF8-encoded file. ----- >>> :t $(embedText "file-embed-lzma.cabal")--- $(embedText "file-embed-lzma.cabal") :: T.Text+-- >>> :t $$(embedText "file-embed-lzma.cabal")+-- $$(embedText "file-embed-lzma.cabal") :: T...Text ---embedText :: FilePath -> Q Exp-embedText fp = [| LT.toStrict |] `appE` embedLazyText fp+embedText :: FilePath -> Code Q T.Text+embedText fp = [|| LT.toStrict $$(embedLazyText fp) ||]++-------------------------------------------------------------------------------+-- TTH helpers+-------------------------------------------------------------------------------++typedSigE :: Code Q a -> Q Type -> Code Q a+typedSigE x a = unsafeCodeCoerce $ sigE (unTypeCode x) a++typedListE :: [Code Q a] -> Code Q [a]+typedListE xs = unsafeCodeCoerce $ listE $ map unTypeCode xs
+ src/FileEmbedLzma/Untyped.hs view
@@ -0,0 +1,113 @@+module FileEmbedLzma.Untyped (+ -- * Embed files+ embedByteString,+ embedLazyByteString,+ embedText,+ embedLazyText,+ -- * Embed directories+ embedDir,+ embedRecursiveDir,+ -- * Internal+ -- ** Directory listing+ listDirectoryFiles,+ listRecursiveDirectoryFiles,+ listDirectoryFilesF,+ -- ** Template Haskell+ lazyBytestringE,+) where++import Language.Haskell.TH (Exp, Q, unTypeCode)++import qualified Data.ByteString.Lazy as LBS+import qualified FileEmbedLzma++-- $setup+-- >>> :set -XTemplateHaskell -dppr-cols=9999+-- >>> import qualified Data.ByteString.Lazy as LBS+-- >>> import qualified Data.ByteString as BS+-- >>> import qualified Data.Text.Lazy as LT+-- >>> import qualified Data.Text as T++-------------------------------------------------------------------------------+-- Directories+-------------------------------------------------------------------------------++-- | Embed a @[('FilePath', 'Data.ByteString.ByteString')]@ list, traversing given directory.+embedDir :: FilePath -> Q Exp+embedDir = unTypeCode . FileEmbedLzma.embedDir++-- | Embed a @[('FilePath', 'Data.ByteString.ByteString')]@ list, recursively traversing given directory path.+--+-- For example, with @wai-static-app@ this can be used as:+--+-- @+-- staticApp $ embeddedSettings $('embedRecursiveDir' "static")+-- -- is an embedded (no data-files!) equivalent of+-- staticApp $ defaultFileServerSettings "static"+-- @+--+--+-- >>> $(embedRecursiveDir "example")+-- [("/Example.hs","..."),("/example.txt","Hello from the inside.\n")]+--+-- >>> :t $(embedRecursiveDir "example")+-- $(embedRecursiveDir "example") :: [(FilePath, BS.ByteString)]+--+embedRecursiveDir :: FilePath -> Q Exp+embedRecursiveDir = unTypeCode . FileEmbedLzma.embedRecursiveDir++-------------------------------------------------------------------------------+-- Strings+-------------------------------------------------------------------------------++-- | Embed a lazy 'Data.ByteString.Lazy.ByteString' from a file.+--+-- >>> :t $(embedLazyByteString "file-embed-lzma.cabal")+-- $(embedLazyByteString "file-embed-lzma.cabal") :: LBS.ByteString+--+embedLazyByteString :: FilePath -> Q Exp+embedLazyByteString = unTypeCode . FileEmbedLzma.embedLazyByteString++-- | Embed a strict 'Data.ByteString.ByteString' from a file.+--+-- >>> :t $(embedByteString "file-embed-lzma.cabal")+-- $(embedByteString "file-embed-lzma.cabal") :: BS...ByteString+--+embedByteString :: FilePath -> Q Exp+embedByteString = unTypeCode . FileEmbedLzma.embedByteString++-- | Embed a lazy 'Data.Text.Lazy.Text' from a UTF8-encoded file.+--+-- >>> :t $(embedLazyText "file-embed-lzma.cabal")+-- $(embedLazyText "file-embed-lzma.cabal") :: LT.Text+--+embedLazyText :: FilePath -> Q Exp+embedLazyText = unTypeCode . FileEmbedLzma.embedLazyText++-- | Embed a strict 'Data.Text.Text' from a UTF8-encoded file.+--+-- >>> :t $(embedText "file-embed-lzma.cabal")+-- $(embedText "file-embed-lzma.cabal") :: T...Text+--+embedText :: FilePath -> Q Exp+embedText = unTypeCode . FileEmbedLzma.embedText++-------------------------------------------------------------------------------+-- Implementation+-------------------------------------------------------------------------------++-- | Makes lazy 'LBS.ByteString' expression.+-- Embedded value is compressed with LZMA.+lazyBytestringE :: LBS.ByteString -> Q Exp+lazyBytestringE = unTypeCode . FileEmbedLzma.lazyBytestringE++listRecursiveDirectoryFiles :: FilePath -> IO [(FilePath, LBS.ByteString)]+listRecursiveDirectoryFiles = FileEmbedLzma.listRecursiveDirectoryFiles++listDirectoryFiles :: FilePath -> IO [(FilePath, LBS.ByteString)]+listDirectoryFiles = FileEmbedLzma.listDirectoryFiles++listDirectoryFilesF+ :: (FilePath -> IO [(FilePath, LBS.ByteString)]) -- ^ what to do with a sub-directory+ -> FilePath -> IO [(FilePath, LBS.ByteString)]+listDirectoryFilesF = FileEmbedLzma.listDirectoryFilesF