This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "snap".

The branch, master has been updated
       via  7e8c42be19f0c6b5f19fc70b748e4ab436cceb48 (commit)
       via  6acf09588a5aa2a4a9eed819f3ffddbdc8ac716c (commit)
      from  b22027fe45175e6f15b0f010c0091a8346f45e4d (commit)


Summary of changes:
 project_template/barebones/foo.cabal               |   35 +++++
 project_template/barebones/src/Main.hs             |   22 +++
 project_template/barebones/src/Server.hs           |  111 ++++++++++++++++
 project_template/default/foo.cabal                 |   37 +++++
 project_template/default/src/Glue.hs               |   46 +++++++
 project_template/default/src/Main.hs               |   30 ++++
 project_template/default/src/Server.hs             |  111 ++++++++++++++++
 project_template/hint/resources/static/favicon.ico |  Bin 0 -> 32038 bytes
 snap.cabal                                         |   51 +++++++
 src/Snap/Loader/Hint.hs                            |  140 ++++++++++++++++++++
 src/Snap/Loader/Static.hs                          |   18 +++
 src/Snap/Starter.hs                                |   97 ++++++++++++++
 src/Snap/StarterTH.hs                              |   55 ++++++++
 13 files changed, 753 insertions(+), 0 deletions(-)
 create mode 100644 project_template/barebones/foo.cabal
 create mode 100644 project_template/barebones/src/Main.hs
 create mode 100644 project_template/barebones/src/Server.hs
 create mode 100644 project_template/default/foo.cabal
 create mode 100644 project_template/default/src/Glue.hs
 create mode 100644 project_template/default/src/Main.hs
 create mode 100644 project_template/default/src/Server.hs
 create mode 100644 project_template/hint/foo.cabal
 create mode 100644 project_template/hint/log/access.log
 create mode 100644 project_template/hint/log/error.log
 create mode 100644 project_template/hint/resources/static/favicon.ico
 create mode 100644 project_template/hint/resources/static/screen.css
 create mode 100644 project_template/hint/resources/templates/index.tpl
 create mode 100644 project_template/hint/src/Config.hs
 create mode 100644 project_template/hint/src/Main.hs
 create mode 100644 project_template/hint/src/Site.hs
 create mode 100644 snap.cabal
 create mode 100644 src/Snap/Loader/Hint.hs
 create mode 100644 src/Snap/Loader/Static.hs
 create mode 100644 src/Snap/Starter.hs
 create mode 100644 src/Snap/StarterTH.hs

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 7e8c42be19f0c6b5f19fc70b748e4ab436cceb48
Author: Carl Howells <[email protected]>
Date:   Mon Jun 21 01:35:19 2010 -0700

    Basic functionality in place for doing hint loading

diff --git a/project_template/barebones/foo.cabal 
b/project_template/barebones/foo.cabal
new file mode 100644
index 0000000..a61c523
--- /dev/null
+++ b/project_template/barebones/foo.cabal
@@ -0,0 +1,35 @@
+Name:                projname
+Version:             0.1
+Synopsis:            Project Synopsis Here
+Description:         Project Description Here
+License:             AllRightsReserved
+Author:              Author
+Maintainer:          [email protected]
+Stability:           Experimental
+Category:            Web
+Build-type:          Simple
+Cabal-version:       >=1.2
+
+Executable projname
+  hs-source-dirs: src
+  main-is: Main.hs
+
+  Build-depends:
+    base >= 4,
+    haskell98,
+    monads-fd >= 0.1 && <0.2,
+    bytestring >= 0.9.1 && <0.10,
+    snap-core >= 0.2 && <0.3,
+    snap-server >= 0.2 && <0.3,
+    xhtml-combinators,
+    unix,
+    text,
+    containers,
+    MonadCatchIO-transformers,
+    filepath >= 1.1 && <1.2
+
+  if impl(ghc >= 6.12.0)
+    ghc-options: -threaded -Wall -fwarn-tabs -funbox-strict-fields -O2
+                 -fno-warn-unused-do-bind
+  else
+    ghc-options: -threaded -Wall -fwarn-tabs -funbox-strict-fields -O2
diff --git a/project_template/barebones/src/Main.hs 
b/project_template/barebones/src/Main.hs
new file mode 100644
index 0000000..1c72738
--- /dev/null
+++ b/project_template/barebones/src/Main.hs
@@ -0,0 +1,22 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Main where
+
+import           Control.Applicative
+import           Snap.Types
+import           Snap.Util.FileServe
+
+import           Server
+
+main :: IO ()
+main = quickServer $
+    ifTop (writeBS "hello world") <|>
+    route [ ("foo", writeBS "bar")
+          , ("echo/:echoparam", echoHandler)
+          ] <|>
+    dir "static" (fileServe ".")
+
+echoHandler :: Snap ()
+echoHandler = do
+    param <- getParam "echoparam"
+    maybe (writeBS "must specify echo/param in URL")
+          writeBS param
diff --git a/project_template/barebones/src/Server.hs 
b/project_template/barebones/src/Server.hs
new file mode 100644
index 0000000..2dd625b
--- /dev/null
+++ b/project_template/barebones/src/Server.hs
@@ -0,0 +1,111 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Server
+    ( ServerConfig(..)
+    , emptyServerConfig
+    , commandLineConfig
+    , server
+    , quickServer
+    ) where
+import qualified Data.ByteString.Char8 as B
+import           Data.ByteString.Char8 (ByteString)
+import           Data.Char
+import           Control.Concurrent
+import           Control.Exception (SomeException)
+import           Control.Monad.CatchIO
+import qualified Data.Text as T
+import           Prelude hiding (catch)
+import           Snap.Http.Server
+import           Snap.Types
+import           Snap.Util.GZip
+import           System hiding (getEnv)
+import           System.Posix.Env
+import qualified Text.XHtmlCombinators.Escape as XH
+
+
+data ServerConfig = ServerConfig
+    { locale          :: String
+    , interface       :: ByteString
+    , port            :: Int
+    , hostname        :: ByteString
+    , accessLog       :: Maybe FilePath
+    , errorLog        :: Maybe FilePath
+    , compression     :: Bool
+    , error500Handler :: SomeException -> Snap ()
+    }
+
+
+emptyServerConfig :: ServerConfig
+emptyServerConfig = ServerConfig
+    { locale          = "en_US"
+    , interface       = "0.0.0.0"
+    , port            = 8000
+    , hostname        = "myserver"
+    , accessLog       = Just "access.log"
+    , errorLog        = Just "error.log"
+    , compression     = True
+    , error500Handler = \e -> do
+        let t = T.pack $ show e
+            r = setContentType "text/html; charset=utf-8" $
+                setResponseStatus 500 "Internal Server Error" emptyResponse
+        putResponse r
+        writeBS "<html><head><title>Internal Server Error</title></head>"
+        writeBS "<body><h1>Internal Server Error</h1>"
+        writeBS "<p>A web handler threw an exception. Details:</p>"
+        writeBS "<pre>\n"
+        writeText $ XH.escape t
+        writeBS "\n</pre></body></html>"
+    }
+
+
+commandLineConfig :: IO ServerConfig
+commandLineConfig = do
+    args <- getArgs
+    let conf = case args of
+         []        -> emptyServerConfig
+         (port':_) -> emptyServerConfig { port = read port' }
+    locale' <- getEnv "LANG"
+    return $ case locale' of
+        Nothing -> conf
+        Just l  -> conf {locale = takeWhile (\c -> isAlpha c || c == '_') l}
+
+server :: ServerConfig -> Snap () -> IO ()
+server config handler = do
+    putStrLn $ "Listening on " ++ (B.unpack $ interface config)
+             ++ ":" ++ show (port config)
+    setUTF8Locale (locale config)
+    try $ httpServe
+             (interface config)
+             (port      config)
+             (hostname  config)
+             (accessLog config)
+             (errorLog  config)
+             (catch500 $ compress $ handler)
+             :: IO (Either SomeException ())
+    threadDelay 1000000
+    putStrLn "Shutting down"
+  where
+    catch500 = (`catch` (error500Handler config))
+    compress = if compression config then withCompression else id
+
+
+quickServer :: Snap () -> IO ()
+quickServer = (commandLineConfig >>=) . flip server
+
+
+setUTF8Locale :: String -> IO ()
+setUTF8Locale locale' = do
+    mapM_ (\k -> setEnv k (locale' ++ ".UTF-8") True)
+          [ "LANG"
+          , "LC_CTYPE"
+          , "LC_NUMERIC"
+          , "LC_TIME"
+          , "LC_COLLATE"
+          , "LC_MONETARY"
+          , "LC_MESSAGES"
+          , "LC_PAPER"
+          , "LC_NAME"
+          , "LC_ADDRESS"
+          , "LC_TELEPHONE"
+          , "LC_MEASUREMENT"
+          , "LC_IDENTIFICATION"
+          , "LC_ALL" ]
diff --git a/project_template/default/foo.cabal 
b/project_template/default/foo.cabal
new file mode 100644
index 0000000..d3e3b7b
--- /dev/null
+++ b/project_template/default/foo.cabal
@@ -0,0 +1,37 @@
+Name:                projname
+Version:             0.1
+Synopsis:            Project Synopsis Here
+Description:         Project Description Here
+License:             AllRightsReserved
+Author:              Author
+Maintainer:          [email protected]
+Stability:           Experimental
+Category:            Web
+Build-type:          Simple
+Cabal-version:       >=1.2
+
+Executable projname
+  hs-source-dirs: src
+  main-is: Main.hs
+
+  Build-depends:
+    base >= 4,
+    haskell98,
+    monads-fd >= 0.1 && <0.2,
+    bytestring >= 0.9.1 && <0.10,
+    snap-core >= 0.2 && <0.3,
+    snap-server >= 0.2 && <0.3,
+    heist >= 0.2.2 && <0.3,
+    hexpat == 0.16,
+    xhtml-combinators,
+    unix,
+    text,
+    containers,
+    MonadCatchIO-transformers,
+    filepath >= 1.1 && <1.2
+
+  if impl(ghc >= 6.12.0)
+    ghc-options: -threaded -Wall -fwarn-tabs -funbox-strict-fields -O2
+                 -fno-warn-unused-do-bind
+  else
+    ghc-options: -threaded -Wall -fwarn-tabs -funbox-strict-fields -O2
diff --git a/project_template/default/src/Glue.hs 
b/project_template/default/src/Glue.hs
new file mode 100644
index 0000000..e6a789c
--- /dev/null
+++ b/project_template/default/src/Glue.hs
@@ -0,0 +1,46 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Glue
+    ( templateHandler
+    , defaultReloadHandler
+    , templateServe
+    , render
+    ) where
+
+import           Control.Applicative
+import           Control.Monad
+import           Data.ByteString.Char8 (ByteString)
+import qualified Data.ByteString.Char8 as B
+import           Prelude hiding (catch)
+import           Snap.Types hiding (dir)
+import           Snap.Util.FileServe
+import           Text.Templating.Heist
+import           Text.Templating.Heist.TemplateDirectory
+
+
+templateHandler :: TemplateDirectory Snap
+                -> (TemplateDirectory Snap -> Snap ())
+                -> (TemplateState Snap -> Snap ())
+                -> Snap ()
+templateHandler td reload f = reload td <|> (f =<< getDirectoryTS td)
+
+
+defaultReloadHandler :: TemplateDirectory Snap -> Snap ()
+defaultReloadHandler td = path "admin/reload" $ do
+    e <- reloadTemplateDirectory td
+    modifyResponse $ setContentType "text/plain; charset=utf-8"
+    writeBS . B.pack $ either id (const "Templates loaded successfully.") e
+
+
+render :: TemplateState Snap -> ByteString -> Snap ()
+render ts template = do
+    bytes <- renderTemplate ts template
+    flip (maybe pass) bytes $ \x -> do
+        modifyResponse $ setContentType "text/html; charset=utf-8"
+        writeBS x
+
+
+templateServe :: TemplateState Snap -> Snap ()
+templateServe ts = ifTop (render ts "index") <|> do
+    path' <- getSafePath
+    when (head path' == '_') pass
+    render ts $ B.pack path'
diff --git a/project_template/default/src/Main.hs 
b/project_template/default/src/Main.hs
new file mode 100644
index 0000000..3254b3b
--- /dev/null
+++ b/project_template/default/src/Main.hs
@@ -0,0 +1,30 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Main where
+
+import           Control.Applicative
+import           Snap.Types
+import           Snap.Util.FileServe
+import           Text.Templating.Heist
+import           Text.Templating.Heist.TemplateDirectory
+
+import           Glue
+import           Server
+
+
+main :: IO ()
+main = do
+    td <- newTemplateDirectory' "templates" emptyTemplateState
+    quickServer $ templateHandler td defaultReloadHandler $ \ts ->
+        ifTop (writeBS "hello world") <|>
+        route [ ("foo", writeBS "bar")
+              , ("echo/:echoparam", echoHandler)
+              ] <|>
+        templateServe ts <|>
+        dir "static" (fileServe ".")
+
+
+echoHandler :: Snap ()
+echoHandler = do
+    param <- getParam "echoparam"
+    maybe (writeBS "must specify echo/param in URL")
+          writeBS param
diff --git a/project_template/default/src/Server.hs 
b/project_template/default/src/Server.hs
new file mode 100644
index 0000000..2dd625b
--- /dev/null
+++ b/project_template/default/src/Server.hs
@@ -0,0 +1,111 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Server
+    ( ServerConfig(..)
+    , emptyServerConfig
+    , commandLineConfig
+    , server
+    , quickServer
+    ) where
+import qualified Data.ByteString.Char8 as B
+import           Data.ByteString.Char8 (ByteString)
+import           Data.Char
+import           Control.Concurrent
+import           Control.Exception (SomeException)
+import           Control.Monad.CatchIO
+import qualified Data.Text as T
+import           Prelude hiding (catch)
+import           Snap.Http.Server
+import           Snap.Types
+import           Snap.Util.GZip
+import           System hiding (getEnv)
+import           System.Posix.Env
+import qualified Text.XHtmlCombinators.Escape as XH
+
+
+data ServerConfig = ServerConfig
+    { locale          :: String
+    , interface       :: ByteString
+    , port            :: Int
+    , hostname        :: ByteString
+    , accessLog       :: Maybe FilePath
+    , errorLog        :: Maybe FilePath
+    , compression     :: Bool
+    , error500Handler :: SomeException -> Snap ()
+    }
+
+
+emptyServerConfig :: ServerConfig
+emptyServerConfig = ServerConfig
+    { locale          = "en_US"
+    , interface       = "0.0.0.0"
+    , port            = 8000
+    , hostname        = "myserver"
+    , accessLog       = Just "access.log"
+    , errorLog        = Just "error.log"
+    , compression     = True
+    , error500Handler = \e -> do
+        let t = T.pack $ show e
+            r = setContentType "text/html; charset=utf-8" $
+                setResponseStatus 500 "Internal Server Error" emptyResponse
+        putResponse r
+        writeBS "<html><head><title>Internal Server Error</title></head>"
+        writeBS "<body><h1>Internal Server Error</h1>"
+        writeBS "<p>A web handler threw an exception. Details:</p>"
+        writeBS "<pre>\n"
+        writeText $ XH.escape t
+        writeBS "\n</pre></body></html>"
+    }
+
+
+commandLineConfig :: IO ServerConfig
+commandLineConfig = do
+    args <- getArgs
+    let conf = case args of
+         []        -> emptyServerConfig
+         (port':_) -> emptyServerConfig { port = read port' }
+    locale' <- getEnv "LANG"
+    return $ case locale' of
+        Nothing -> conf
+        Just l  -> conf {locale = takeWhile (\c -> isAlpha c || c == '_') l}
+
+server :: ServerConfig -> Snap () -> IO ()
+server config handler = do
+    putStrLn $ "Listening on " ++ (B.unpack $ interface config)
+             ++ ":" ++ show (port config)
+    setUTF8Locale (locale config)
+    try $ httpServe
+             (interface config)
+             (port      config)
+             (hostname  config)
+             (accessLog config)
+             (errorLog  config)
+             (catch500 $ compress $ handler)
+             :: IO (Either SomeException ())
+    threadDelay 1000000
+    putStrLn "Shutting down"
+  where
+    catch500 = (`catch` (error500Handler config))
+    compress = if compression config then withCompression else id
+
+
+quickServer :: Snap () -> IO ()
+quickServer = (commandLineConfig >>=) . flip server
+
+
+setUTF8Locale :: String -> IO ()
+setUTF8Locale locale' = do
+    mapM_ (\k -> setEnv k (locale' ++ ".UTF-8") True)
+          [ "LANG"
+          , "LC_CTYPE"
+          , "LC_NUMERIC"
+          , "LC_TIME"
+          , "LC_COLLATE"
+          , "LC_MONETARY"
+          , "LC_MESSAGES"
+          , "LC_PAPER"
+          , "LC_NAME"
+          , "LC_ADDRESS"
+          , "LC_TELEPHONE"
+          , "LC_MEASUREMENT"
+          , "LC_IDENTIFICATION"
+          , "LC_ALL" ]
diff --git a/project_template/hint/foo.cabal b/project_template/hint/foo.cabal
new file mode 100644
index 0000000..e69de29
diff --git a/project_template/hint/log/access.log 
b/project_template/hint/log/access.log
new file mode 100644
index 0000000..e69de29
diff --git a/project_template/hint/log/error.log 
b/project_template/hint/log/error.log
new file mode 100644
index 0000000..e69de29
diff --git a/project_template/hint/resources/static/favicon.ico 
b/project_template/hint/resources/static/favicon.ico
new file mode 100644
index 0000000..af01ed3
Binary files /dev/null and b/project_template/hint/resources/static/favicon.ico 
differ
diff --git a/project_template/hint/resources/static/screen.css 
b/project_template/hint/resources/static/screen.css
new file mode 100644
index 0000000..e69de29
diff --git a/project_template/hint/resources/templates/index.tpl 
b/project_template/hint/resources/templates/index.tpl
new file mode 100644
index 0000000..e69de29
diff --git a/project_template/hint/src/Config.hs 
b/project_template/hint/src/Config.hs
new file mode 100644
index 0000000..e69de29
diff --git a/project_template/hint/src/Main.hs 
b/project_template/hint/src/Main.hs
new file mode 100644
index 0000000..e69de29
diff --git a/project_template/hint/src/Site.hs 
b/project_template/hint/src/Site.hs
new file mode 100644
index 0000000..e69de29
diff --git a/src/Snap/Starter.hs b/src/Snap/Starter.hs
new file mode 100644
index 0000000..bddb339
--- /dev/null
+++ b/src/Snap/Starter.hs
@@ -0,0 +1,97 @@
+{-# LANGUAGE TemplateHaskell #-}
+module Snap.Starter where
+
+------------------------------------------------------------------------------
+import           Data.List
+import qualified Data.Text as T
+import           System
+import           System.Directory
+import           System.Console.GetOpt
+import           System.FilePath
+------------------------------------------------------------------------------
+
+import Snap.StarterTH
+
+
+------------------------------------------------------------------------------
+-- Creates a value tDir :: ([String], [(String, String)])
+$(buildData "tDirDefault"   "default")
+$(buildData "tDirBareBones" "barebones")
+$(buildData "tDirHint"      "hint")
+
+------------------------------------------------------------------------------
+usage :: String
+usage = unlines
+    ["Usage:"
+    ,""
+    ,"  snap <action>"
+    ,""
+    ,"    <action> can be one of:"
+    ,"      init - create a new project directory structure in the current 
directory"
+    ]
+
+
+------------------------------------------------------------------------------
+data InitFlag = InitBareBones
+              | InitHelp
+  deriving (Show, Eq)
+
+
+setup :: String -> ([FilePath], [(String, String)]) -> IO ()
+setup projName tDir = do
+    mapM createDirectory (fst tDir)
+    mapM_ write (snd tDir)
+  where
+    write (f,c) =
+        if isSuffixOf "foo.cabal" f
+          then writeFile (projName++".cabal") (insertProjName $ T.pack c)
+          else writeFile f c
+    insertProjName c = T.unpack $ T.replace
+                           (T.pack "projname")
+                           (T.pack projName) c
+
+------------------------------------------------------------------------------
+initProject :: [String] -> IO ()
+initProject args = do
+    case getOpt Permute options args of
+      (flags, _, [])
+        | InitHelp `elem` flags -> do putStrLn initUsage
+                                      exitFailure
+        | otherwise             -> init' (InitBareBones `elem` flags)
+
+      (_, _, errs) -> do putStrLn $ concat errs
+                         putStrLn initUsage
+                         exitFailure
+  where
+    initUsage = unlines
+        ["Usage:"
+        ,""
+        ,"  snap init"
+        ,""
+        ,"    -b  --barebones   Depend only on -core and -server"
+        ,"    -h  --help        Print this message"
+        ]
+
+    options =
+        [ Option ['b'] ["barebones"] (NoArg InitBareBones)
+                 "Depend only on -core and -server"
+        , Option ['h'] ["help"]      (NoArg InitHelp)
+                 "Print this message"
+        ]
+
+    init' isBareBones = do
+        cur <- getCurrentDirectory
+        let dirs = splitDirectories cur
+            projName = last dirs
+        setup projName (if isBareBones then tDirBareBones else tDirDefault)
+
+
+------------------------------------------------------------------------------
+main :: IO ()
+main = do
+    args <- getArgs
+    case args of
+        ("init":args') -> initProject args'
+        _              -> do putStrLn usage
+                             exitFailure
+
diff --git a/src/Snap/StarterTH.hs b/src/Snap/StarterTH.hs
new file mode 100644
index 0000000..17f8cce
--- /dev/null
+++ b/src/Snap/StarterTH.hs
@@ -0,0 +1,55 @@
+{-# LANGUAGE TemplateHaskell #-}
+module Snap.StarterTH where
+
+------------------------------------------------------------------------------
+import qualified Data.Foldable as F
+import           Data.List
+import           Language.Haskell.TH
+import           System.Directory.Tree
+------------------------------------------------------------------------------
+
+
+------------------------------------------------------------------------------
+-- Convenience types
+type FileData = (String, String)
+type DirData = FilePath
+
+
+------------------------------------------------------------------------------
+-- Gets all the directorys in a DirTree
+getDirs :: [FilePath] -> DirTree a -> [FilePath]
+getDirs prefix (Dir n c) = (intercalate "/" (reverse (n:prefix))) : concatMap 
(getDirs (n:prefix)) c
+getDirs _ (File _ _) = []
+getDirs _ (Failed _ _) = []
+
+
+------------------------------------------------------------------------------
+-- Reads a directory and returns a tuple of the list of all directories
+-- encountered and a list of filenames and content strings.
+readTree :: FilePath -> IO ([DirData], [FileData])
+readTree dir = do
+    d <- readDirectory $ dir++"/."
+    let ps = zipPaths $ "" :/ (free d)
+        fd = F.foldr (:) [] ps
+        dirs = tail $ getDirs [] $ free d
+    return $ (dirs, fd)
+
+
+------------------------------------------------------------------------------
+-- Calls readTree and returns it's value in a quasiquote.
+dirQ :: FilePath -> Q Exp
+dirQ tplDir = do
+    d <- runIO $ readTree $ "project_template/"++tplDir
+    runQ [| d |]
+
+
+------------------------------------------------------------------------------
+-- Creates a declaration assigning the specified name the value returned by
+-- dirQ.
+buildData :: String -> FilePath -> Q [Dec]
+buildData dirName tplDir = do
+    v <- valD (varP (mkName dirName))
+                    (normalB $ dirQ tplDir)
+                    []
+    return [v]
+
commit 6acf09588a5aa2a4a9eed819f3ffddbdc8ac716c
Author: Carl Howells <[email protected]>
Date:   Sat Jun 19 03:57:06 2010 -0700

    loader modules to compiling state

diff --git a/snap.cabal b/snap.cabal
new file mode 100644
index 0000000..d8b2dfe
--- /dev/null
+++ b/snap.cabal
@@ -0,0 +1,51 @@
+name:           snap
+version:        0.3
+synopsis:       Snap: A Haskell Web Framework (Core)
+
+description:
+  This is the first developer prerelease of the Snap framework.  Snap is a
+  simple and fast web development framework and server written in Haskell. For
+  more information or to download the latest version, you can visit the Snap
+  project website at <http://snapframework.com/>.
+  .
+
+license:        BSD3
+license-file:   LICENSE
+author:         James Sanders, Shu-yu Guo, Gregory Collins, Doug Beardsley
+maintainer:     [email protected]
+build-type:     Simple
+cabal-version:  >= 1.6
+homepage:       http://snapframework.com/
+category:       Web
+
+extra-source-files:
+  CONTRIBUTORS,
+  LICENSE,
+  README.md,
+  README.SNAP.md
+
+Library
+  hs-source-dirs: src
+
+  exposed-modules:
+    Snap.Loader.Static,
+    Snap.Loader.Hint
+
+  build-depends:
+    base >= 4 && < 5,
+    bytestring >= 0.9.1 && < 0.10,
+    directory >= 1.0.0.0 && < 1.1,
+    filepath >= 1.0 && < 1.2,
+    monads-fd >= 0.1 && < 0.2,
+    snap-core >= 0.2.7 && < 0.3,
+    heist >= 0.2.1 && < 0.3,
+    hint >= 0.3.2 && < 0.4,
+    template-haskell >= 2.3 && < 2.5,
+    time >= 1.0 && < 1.3
+
+  if impl(ghc >= 6.12.0)
+    ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2
+                 -fno-warn-unused-do-bind
+  else
+    ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2
+
diff --git a/src/Snap/Loader/Hint.hs b/src/Snap/Loader/Hint.hs
new file mode 100644
index 0000000..cb5683b
--- /dev/null
+++ b/src/Snap/Loader/Hint.hs
@@ -0,0 +1,140 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+module Snap.Loader.Hint where
+
+------------------------------------------------------------------------------
+import qualified Data.ByteString.Char8 as S
+
+import           Data.List (nub)
+
+import           Control.Concurrent (forkIO)
+import           Control.Concurrent.MVar
+import           Control.Monad (when)
+import           Control.Monad.Trans (liftIO)
+
+import           Data.Maybe (catMaybes)
+import           Data.Time.Clock
+
+import           Language.Haskell.Interpreter hiding (lift, liftIO)
+import           Language.Haskell.Interpreter.Unsafe (unsafeSetGhcOption)
+
+import           Language.Haskell.TH.Syntax
+
+import           System.Directory (getCurrentDirectory)
+import           System.FilePath ((</>))
+
+------------------------------------------------------------------------------
+import           Snap.Types
+
+
+
+------------------------------------------------------------------------------
+-- | XXX
+-- Assumes being spliced into the same source tree as the action to
+-- dynamically load is located in
+-- Assumes mtl is the only package installed with a conflicting
+-- Control.Monad.Trans
+loadSnapTH :: Name -> Name -> Q Exp
+loadSnapTH initialize action = do
+    loc <- location
+    cwd <- runIO getCurrentDirectory
+
+    let initMod = nameModule initialize
+        initBase = nameBase initialize
+        actMod = nameModule action
+        actBase = nameBase action
+
+        lf = length . loc_filename $ loc
+        lm = length . loc_module $ loc
+        relSrc = if lf > lm + 4
+                 then take (lf - (lm + 4)) $ loc_filename loc
+                 else "."
+        src = cwd </> relSrc
+        str = "liftIO " ++ initBase ++ " >>= " ++ actBase
+        modules = catMaybes [initMod, actMod]
+        opts = [ "-hide-package=mtl" ] :: [String]
+
+        hintSnapE = VarE 'hintSnap
+
+    optsE <- lift opts
+    srcE <- lift src
+    modulesE <- lift modules
+    strE <- lift str
+
+    return $ foldl AppE hintSnapE [optsE, srcE, modulesE, strE]
+
+
+------------------------------------------------------------------------------
+-- | XXX
+hintSnap :: [String] -> String -> [String] -> String -> IO (Snap ())
+hintSnap opts sPath mNames action = do
+    let interpreter = do
+        mapM_ unsafeSetGhcOption opts
+        set [ searchPath := [sPath] ]
+        loadModules . nub $ mNames
+        let allMods = "Prelude":"Snap.Types":"Control.Monad.Trans":mNames
+        setImports . nub $ allMods
+        interpret action (as :: Snap ())
+
+    loadAction <- protectedActionEvaluator 3 $ runInterpreter interpreter
+
+    return $ do
+        eSnap <- liftIO loadAction
+        case eSnap of
+            Left err -> do
+                let msg = format err
+                    len = fromIntegral $ S.length msg
+                modifyResponse $ setContentType "text/plain; charset=utf-8"
+                               . setResponseStatus 500 "Internal Server Error"
+                               . setContentLength len
+                writeBS msg
+
+            Right handler -> handler
+
+
+------------------------------------------------------------------------------
+-- |
+format :: InterpreterError -> S.ByteString
+format (UnknownError e)   =
+    S.append "Unknown interpreter error:\r\n\r\n" $ S.pack e
+
+format (NotAllowed e)     =
+    S.append "Interpreter action not allowed:\r\n\r\n" $ S.pack e
+
+format (GhcException e)   =
+    S.append "GHC error:\r\n\r\n" $ S.pack e
+
+format (WontCompile errs) =
+    let formatted = S.intercalate "\r\n" . map S.pack . nub . map errMsg $ errs
+    in S.append "Compile errors:\r\n\r\n" formatted
+
+
+------------------------------------------------------------------------------
+-- | XXX
+protectedActionEvaluator :: NominalDiffTime -> IO a -> IO (IO a)
+protectedActionEvaluator minReEval action = do
+    readerContainer <- newMVar []
+    resultContainer <- newMVar Nothing
+    return $ do
+        existingResult <- readMVar resultContainer
+        now <- getCurrentTime
+
+        case existingResult of
+            Just (val, ts) | diffUTCTime now ts < minReEval -> return val
+            _ -> do
+                reader <- newEmptyMVar
+                readers <- takeMVar readerContainer
+
+                when (null readers) $ do
+                    forkIO $ do
+                        result <- action
+                        allReaders <- takeMVar readerContainer
+                        finishTime <- getCurrentTime
+                        swapMVar resultContainer $ Just (result, finishTime)
+                        putMVar readerContainer []
+                        mapM_ (flip putMVar result) allReaders
+                    return ()
+
+                putMVar readerContainer $ reader : readers
+                takeMVar reader
diff --git a/src/Snap/Loader/Static.hs b/src/Snap/Loader/Static.hs
new file mode 100644
index 0000000..b3ac8b1
--- /dev/null
+++ b/src/Snap/Loader/Static.hs
@@ -0,0 +1,18 @@
+{-# LANGUAGE TemplateHaskell #-}
+
+module Snap.Loader.Static where
+
+------------------------------------------------------------------------------
+import           Language.Haskell.TH.Syntax
+
+
+------------------------------------------------------------------------------
+-- | XXX
+
+loadSnapTH :: Name -> Name -> Q Exp
+loadSnapTH init action = do
+    let initE = VarE init
+        actE = VarE action
+        fmapE = VarE 'fmap
+        simpleLoad = foldl AppE fmapE [actE, initE]
+    return simpleLoad
-----------------------------------------------------------------------


hooks/post-receive
-- 
snap
_______________________________________________
Snap mailing list
[email protected]
http://mailman-mail5.webfaction.com/listinfo/snap

Reply via email to