git.iko.soy/typeable/servant-swagger-ui
on master help sign in
Single BSL for whole directory
commit993cc7dddbfde0667619dd12f9a44404c46c625c authorOleg Grenrus <oleg.grenrus@iki.fi> dateWed 4 Apr 2018, 22:24 (9 years ago) parent869edb7
3 files changed+70−23
servant-swagger-ui.cabal+3−2 src/Servant/Swagger/UI.hs+2−3 src/Servant/Swagger/UI/Internal.hs+65−18
servant-swagger-ui.cabal+3−2
@@ -97,10 +97,10 @@ library
9797
9898 build-depends:
9999 base >=4.7 && <4.12
100+ , base-compat >=0.9.3 && <0.10
100101 , blaze-markup >=0.7.0.2 && <0.9
101102 , bytestring >=0.10.4.0 && <0.11
102103 , directory >=1.2.1.0 && <1.4
103− , file-embed >=0.0.9 && <0.1
104104 , filepath >=1.3.0.2 && <1.5
105105 , http-media >=0.6.2 && <0.8
106106 , lzma >=0.0.0.3 && <0.1
@@ -111,11 +111,12 @@ library
111111 , swagger2 >=2.0.1 && <2.3
112112 , template-haskell >=2.9 && <2.14
113113 , text >=1.2.0.6 && <1.3
114+ , th-lift-instances >=0.1.11 && <0.2
115+ , transformers >=0.3 && <0.6
114116 , wai-app-static >=3.0.1.1 && <3.2
115117 if flag(servant-0-5)
116118 build-depends:
117119 servant >=0.5
118− , transformers >=0.3 && <0.6
119120 , transformers-compat >=0.3 && <0.6
120121 else
121122 build-depends:
src/Servant/Swagger/UI.hs+2−3
@@ -70,7 +70,6 @@ module Servant.Swagger.UI (
7070 ) where
7171
7272import Data.ByteString (ByteString)
73−import Data.FileEmbed (embedStringFile)
7473import Data.Swagger (Swagger)
7574import GHC.TypeLits (KnownSymbol, Symbol, symbolVal)
7675import Network.Wai.Application.Static (embeddedSettings, staticApp)
@@ -190,13 +189,13 @@ swaggerSchemaUIServerImpl indexTemplate files swagger = return swagger
190189 staticApp $ embeddedSettings files
191190
192191swaggerUiIndexTemplate :: T.Text
193−swaggerUiIndexTemplate = $(embedStringFile "index.html.tmpl")
192+swaggerUiIndexTemplate = $(embedText "index.html.tmpl")
194193
195194swaggerUiFiles :: [(FilePath, ByteString)]
196195swaggerUiFiles = $(mkRecursiveEmbedded "swagger-ui-dist-3.9.1")
197196
198197jensolegIndexTemplate :: T.Text
199−jensolegIndexTemplate = $(embedStringFile "jensoleg.index.html.tmpl")
198+jensolegIndexTemplate = $(embedText "jensoleg.index.html.tmpl")
200199
201200jensolegFiles :: [(FilePath, ByteString)]
202201jensolegFiles = $(mkRecursiveEmbedded "jensoleg-dist")
src/Servant/Swagger/UI/Internal.hs+65−18
@@ -11,24 +11,35 @@
1111-- Originally from waitra package:
1212-- <http://hackage.haskell.org/package/waitra-0.0.4.0/docs/Network-Waitra-Embedded.html>
1313----------------------------------------------------------------------------
14−module Servant.Swagger.UI.Internal (mkRecursiveEmbedded) where
14+module Servant.Swagger.UI.Internal (mkRecursiveEmbedded, embedText) where
1515
16−import qualified Codec.Compression.Lzma as LZMA
17−import Control.Arrow (first)
18−import Control.Monad (forM)
19−import qualified Data.ByteString as BS
20−import qualified Data.ByteString.Lazy as BSL
21−import qualified Data.ByteString.Unsafe as BS.Unsafe
22−import Language.Haskell.TH
23−import System.Directory
24− (doesDirectoryExist, getDirectoryContents)
25−import System.FilePath (makeRelative, (</>))
26−import System.IO.Unsafe (unsafePerformIO)
16+import Prelude ()
17+import Prelude.Compat
18+
19+import Control.Arrow (first)
20+import Control.Monad (forM)
21+import Control.Monad.Trans.State.Strict (runState, state)
22+import Data.Functor.Compose (Compose (..))
23+import Data.Int (Int64)
24+import Language.Haskell.TH
25+import System.Directory
26+ (doesDirectoryExist, getDirectoryContents)
27+import System.FilePath (makeRelative, (</>))
28+import System.IO.Unsafe (unsafePerformIO)
29+
30+import qualified Codec.Compression.Lzma as LZMA
31+import qualified Data.ByteString as BS
32+import qualified Data.ByteString.Lazy as BSL
33+import qualified Data.ByteString.Unsafe as BS.Unsafe
34+import qualified Data.Text.Lazy as TL
35+import qualified Data.Text.Lazy.Encoding as TLE
36+
37+import Instances.TH.Lift ()
2738
2839getRecursiveContents :: FilePath -> IO [(FilePath, BSL.ByteString)]
2940getRecursiveContents topdir = do
3041 names <- getDirectoryContents topdir
31− let properNames = Prelude.filter (`notElem` [".", ".."]) names
42+ let properNames = filter (`notElem` [".", ".."]) names
3243 paths <- forM properNames $ \name -> do
3344 let path = topdir </> name
3445 isDirectory <- doesDirectoryExist path
@@ -51,12 +62,33 @@ lazyBytestringE lbs =
5162 $ BS.Unsafe.unsafePackAddressLen $l $s
5263 |]
5364 where
54− bs = BSL.toStrict $ LZMA.compress lbs
65+ bs = BSL.toStrict $ LZMA.compressWith params lbs
5566 s = litE $ stringPrimL $ BS.unpack bs
5667 l = litE $ integerL $ fromIntegral $ BS.length bs
5768
58−makeEmbeddedEntry :: (FilePath, BSL.ByteString) -> Q Exp
59−makeEmbeddedEntry (path, bs) = [| (path, BSL.toStrict $(lazyBytestringE bs)) |]
69+ params = LZMA.defaultCompressParams
70+ {- doesn't seem to affect much
71+ { LZMA.compressLevel = LZMA.CompressionLevel9
72+ , LZMA.compressLevelExtreme = True
73+ }
74+ -}
75+
76+makeEmbeddedEntry :: Name -> (FilePath, (Int64, Int64)) -> Q Exp
77+makeEmbeddedEntry name (path, (off, len)) =
78+ [| (path, BSL.toStrict $ BSL.take len $ BSL.drop off $(varE name)) |]
79+
80+concatEntries :: Traversable t => t BSL.ByteString -> (BSL.ByteString, t (Int64, Int64))
81+concatEntries xs = (bslEndo BSL.empty, ys)
82+ where
83+ (ys, (_, bslEndo)) = runState (traverse (state . single) xs) (0, id)
84+
85+ single
86+ :: BSL.ByteString -- file bytestring
87+ -> (Int64, BSL.ByteString -> BSL.ByteString) -- current offset, buffer so far
88+ -> ((Int64, Int64), (Int64, BSL.ByteString -> BSL.ByteString))
89+ single bsl (off, endo) = ((off, l), (off + l, endo . BSL.append bsl))
90+ where
91+ l = fromIntegral $ BSL.length bsl
6092
6193-- | Create a @[('FilePath', 'BSL.ByteString')]@ list, recursively traversing given directory path.
6294--
@@ -65,5 +97,20 @@ makeEmbeddedEntry (path, bs) = [| (path, BSL.toStrict $(lazyBytestringE bs)) |]
6597-- > staticApp $ defaultFileServerSettings "static"
6698mkRecursiveEmbedded :: FilePath -> Q Exp
6799mkRecursiveEmbedded topdir = do
68− pairs <- runIO $ fmap (makeAllRelative topdir) $ getRecursiveContents topdir
69− listE $ map makeEmbeddedEntry pairs
100+ pairs <- runIO $ fmap (makeAllRelative topdir) $ getRecursiveContents topdir
101+ -- we do a hop to only embed single big bytestring.
102+ -- it's beneficial as lzma have more stuff to compress
103+ let (bsl, Compose offsets) = concatEntries (Compose pairs)
104+ bslName <- newName "embedBsl"
105+ bslExpr <- lazyBytestringE bsl
106+ letE [ return $ ValD (VarP bslName) (NormalB bslExpr) [] ] $
107+ listE $ map (makeEmbeddedEntry bslName) offsets
108+
109+-- | Create a textual 'T.Text' from a UTF8-encoded file.
110+embedText :: FilePath -> Q Exp
111+embedText fp = do
112+ bsl <- runIO $ BSL.readFile fp
113+ case TLE.decodeUtf8' bsl of
114+ Left e -> reportError (show e)
115+ Right _ -> return ()
116+ [| TL.toStrict $ TLE.decodeUtf8 $ $(lazyBytestringE bsl) |]