packages feed

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 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