git.iko.soy/typeable/file-embed
on master help sign in
Initial working version with sample, undocumented
commitc6f5fc348fedf6cd1121e60e5f8049569fbefd69 authorMichael Snoyman <michael@snoyman.com> dateThu 23 Jul 2009, 21:42 (17 years ago) parentb4cf151
10 files changed+132
.gitignore+2 Data/FileEmbed.hs+61 LICENSE+25 README+1 Setup.lhs+7 file-embed.cabal+18 sample/bar+1 sample/baz+1 sample/bin+1 test.hs+15
.gitignorenew file+2
@@ -0,0 +1,2 @@
1+dist
2+*.swp
Data/FileEmbed.hsnew file+61
@@ -0,0 +1,61 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+module Data.FileEmbed
3+ ( embedFile
4+ , embedDir
5+ ) where
6+
7+import Language.Haskell.TH (runQ,
8+ Exp(AppE, ListE, LitE, TupE),
9+ Lit(IntegerL, StringL),
10+ Q,
11+ runIO)
12+import System.Directory (doesDirectoryExist, doesFileExist,
13+ getDirectoryContents)
14+import Control.Monad (filterM)
15+import qualified Data.ByteString as B
16+import Control.Arrow ((&&&), second, first)
17+import Control.Applicative ((<$>))
18+import Data.Monoid (mappend)
19+
20+embedFile :: FilePath -> Q Exp
21+embedFile fp = (runIO $ B.readFile fp) >>= bsToExp
22+
23+embedDir :: FilePath -> Q Exp
24+embedDir fp = ListE <$> ((runIO $ fileList fp) >>= mapM pairToExp)
25+
26+pairToExp :: (FilePath, B.ByteString) -> Q Exp
27+pairToExp (path, bs) = do
28+ exp' <- bsToExp bs
29+ return $! TupE [LitE $ StringL path, exp']
30+
31+bsToExp :: B.ByteString -> Q Exp
32+bsToExp bs = do
33+ pack <- runQ [| B.pack |]
34+ return $!
35+ AppE pack .
36+ ListE .
37+ map (LitE . IntegerL . fromIntegral) .
38+ B.unpack $
39+ bs
40+
41+notHidden :: FilePath -> Bool
42+notHidden ('.':_) = False
43+notHidden _ = True
44+
45+fileList :: FilePath -> IO [(FilePath, B.ByteString)]
46+fileList top = map (first tail) <$> fileList' top ""
47+
48+fileList' :: FilePath -> FilePath -> IO [(FilePath, B.ByteString)]
49+fileList' realTop top = do
50+ let prefix1 = top ++ "/"
51+ prefix2 = realTop ++ prefix1
52+ allContents <- filter notHidden <$> getDirectoryContents prefix2
53+ let all' = map (mappend prefix1 &&& mappend prefix2) allContents
54+ files <- filterM (doesFileExist . snd) all' >>=
55+ mapM (liftPair2 . second B.readFile)
56+ dirs <- filterM (doesDirectoryExist . snd) all' >>=
57+ mapM (fileList' realTop . fst)
58+ return $ concat $ files : dirs
59+
60+liftPair2 :: Monad m => (a, m b) -> m (a, b)
61+liftPair2 (a, b) = b >>= \b' -> return (a, b')
LICENSEnew file+25
@@ -0,0 +1,25 @@
1+The following license covers this documentation, and the source code, except
2+where otherwise indicated.
3+
4+Copyright 2008, Michael Snoyman. All rights reserved.
5+
6+Redistribution and use in source and binary forms, with or without
7+modification, are permitted provided that the following conditions are met:
8+
9+* Redistributions of source code must retain the above copyright notice, this
10+ list of conditions and the following disclaimer.
11+
12+* Redistributions in binary form must reproduce the above copyright notice,
13+ this list of conditions and the following disclaimer in the documentation
14+ and/or other materials provided with the distribution.
15+
16+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY EXPRESS OR
17+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19+EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
20+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
22+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
24+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
README+1
@@ -0,0 +1 @@
1+Use Template Haskell to embed file contents directly.
Setup.lhsnew file+7
@@ -0,0 +1,7 @@
1+#!/usr/bin/env runhaskell
2+
3+> module Main where
4+> import Distribution.Simple
5+
6+> main :: IO ()
7+> main = defaultMain
file-embed.cabalnew file+18
@@ -0,0 +1,18 @@
1+name: file-embed
2+version: 0.0.0
3+license: BSD3
4+license-file: LICENSE
5+author: Michael Snoyman <michael@snoyman.com>
6+maintainer: Michael Snoyman <michael@snoyman.com>
7+synopsis: Use Template Haskell to embed file contents directly.
8+description: FIXME
9+category: Data
10+stability: unstable
11+cabal-version: >= 1.2
12+build-type: Simple
13+homepage: http://github.com/snoyberg/file-embed/tree/master
14+
15+library
16+ build-depends: base
17+ exposed-modules:
18+ ghc-options: -Wall
sample/barnew file+1
@@ -0,0 +1 @@
1+bar bar bar
sample/baznew file+1
@@ -0,0 +1 @@
1+baz baz baz
sample/binnew file+1
@@ -0,0 +1 @@
1+bin bin bin
test.hsnew file+15
@@ -0,0 +1,15 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+import Data.FileEmbed
4+import qualified Data.ByteString as B
5+
6+plainfile :: B.ByteString
7+plainfile = $(embedFile "sample/bar")
8+
9+plaindir :: [(FilePath, B.ByteString)]
10+plaindir = $(embedDir "sample")
11+
12+main :: IO ()
13+main = do
14+ print plainfile
15+ print plaindir