module Development.Cake3.Rules.UrWeb(
urweb
, Config(..)
, defaultConfig
, urdeps
) where
import Data.Monoid
import Data.List
import Data.Set (member)
import Control.Applicative
import Control.Monad.Trans
import Control.Monad.State
import System.Directory
import System.IO as IO
import System.FilePath.Wrapper
import Development.Cake3
import Development.Cake3.Types
import Development.Cake3.Monad as C3
splitWhen c l = (h,if null t then [] else tail t) where
(h,t) = span (/=c) l
urpparse :: (Monad m) => String -> ((String,String) -> m ()) -> (FilePath -> m ()) -> m ()
urpparse inp hact sact = do
parseline False (lines inp) where
parseline _ [] = return ()
parseline False (l:ls)
| (unwords (words l)) == [] = parseline True ls
| otherwise = hact (splitWhen ' ' l) >> parseline False ls
parseline True (l:ls) = sact l >> parseline True ls
data Config = Config {
urObjRule :: File -> Rule
, urInclude :: Variable
, urEmbed :: [(String, [File])]
}
defaultConfig = Config {
urObjRule = \f -> rule f (fail "urobj: not set")
, urInclude = makevar "UR_INCLUDE_DIR" "/usr/local/include/urweb"
, urEmbed = []
}
urdeps :: Config -> File -> A ()
urdeps cfg f = do
ps <- prerequisites
let check = msum [ lookup (unpack (takeBaseName f)) (urEmbed cfg)
, lookup (unpack (takeFileName f)) (urEmbed cfg)
]
case check of
Just embeddable -> do
depend (urembed cfg f embeddable)
Nothing -> do
depend f
inp <- C3.readFile f
urpparse inp lib src
where
relative x = takeDirectory f </> (fromFilePath x)
lib (h,x)
| (h=="library") = do
let nested = relative x
isdir <- liftIO $ doesDirectoryExist (unpack nested)
case isdir of
True -> urdeps cfg (nested </> (fromFilePath "lib.urp"))
False -> urdeps cfg (nested .= "urp")
| (h=="ffi") = do
depend ((relative x) .= "urs")
| (h=="include") = do
depend (relative x)
| (h=="link") = do
depend (urObjRule cfg (relative x))
| otherwise = return ()
src d@(c:_)
| (c/='$') = do
depend ((relative d) .= "ur" :: File)
let urs = (relative d) .= "urs"
e <- liftIO $ doesFileExist (toFilePath urs)
when e $ do
depend ((relative d) .= "urs" :: File)
| otherwise = return ()
src _ = return ()
urpline :: String -> File -> String -> IO File
urpline sect f c = flip execStateT mempty $ urpparse c lib (const $ return ()) where
relative x = takeDirectory f </> (fromFilePath x)
lib (n,x) | n == sect = put (relative x)
| otherwise = return ()
urpdb :: String -> File -> String -> IO File
urpdb dbsect f c = flip execStateT mempty $ urpparse c lib (const $ return ()) where
relative x = takeDirectory f </> (fromFilePath x)
lib (n,x) | n == "database" = put (relative $ snd (splitWhen '=' x))
| otherwise = return ()
urpexe :: File -> File
urpexe f = f .= "exe"
urweb :: Config -> File -> A() -> IO (Alias, Alias, Alias)
urweb cfg f act = do
c <- liftIO (IO.readFile $ unpack f)
exe <- return (urpexe f)
sql <- urpline "sql" f c
db <- urpdb "name" f c
ruleM (exe,sql,db) (act >> urdeps cfg f)
urembed :: Config -> File -> [File] -> Alias
urembed cfg urp files =
let
dir = takeDirectory urp
makefile = (dir </> takeBaseName urp) .= "mk"
dir_ = string dir
urp_ = string urp
mf_ = string (takeFileName makefile)
in rule urp $ do
let urcc = makevar "URCC" "$(shell urweb -print-ccompiler)"
let gcc = makevar "CC" "$(shell $(URCC) -print-prog-name=gcc)"
let ld = makevar "LD" "$(shell $(URCC) -print-prog-name=ld)"
let mf = rule makefile $ do
shell [cmd|mkdir pv $(dir_)|]
shell [cmd|urembed o $(urp_) $files|]
depend urcc
depend mf
shell [cmd|$(extvar "MAKE") C $(dir_) f $(mf_) CC=$gcc LD=$ld UR_INCLUDE_DIR=$(urInclude cfg) urp|]