{-# LANGUAGE DoAndIfThenElse #-} -- ---------------------------------------------------------------------------- {- | Main module for the executable. -} -- ---------------------------------------------------------------------------- module Main where import Control.Applicative ((<$>), (<|>)) import Control.Monad (when) import Data.Aeson (decode) import Data.Aeson.Encode.Pretty (encodePretty) import Data.ByteString.Lazy (ByteString) -- import Data.Char (toUpper) -- import Data.Map (keys) import Data.Maybe (fromJust) import Data.String.Conversions (cs) import Data.Text (Text) import Data.Time.Clock.POSIX (getPOSIXTime) import System.Console.Docopt (argument, command, getArg, isPresent, longOption, optionsWithUsage) import System.Environment (getArgs) import qualified System.IO as System (stderr) import qualified System.Log.Formatter as Log (simpleLogFormatter) import qualified System.Log.Handler as Log (setFormatter) import qualified System.Log.Handler.Simple as Log (streamHandler) import qualified System.Log.Logger as Log import qualified Hunt.ClientInterface as H import qualified Hunt.Converter.CSV as CSV (convert) import qualified Hunt.Server.Client as HC usage :: String usage = unlines [ "hunt-server-cli" , "" , "Usage:" , " hunt-server-cli eval [--server SERVER] " , " hunt-server-cli load [--server SERVER] " , " hunt-server-cli store [--server SERVER] " , " hunt-server-cli search [--server SERVER] [--max MAX] [--offset OFFSET] " , " hunt-server-cli completion [--server SERVER] " , " hunt-server-cli make-schema " , " hunt-server-cli make-insert " , " hunt-server-cli from-csv " , "" , "" , "Options:" , " -h --help Show this screen." , " --server=SERVER Use this hunt server [default: http://localhost:3000]" , " --max=MAX Request at most MAX results [default: 20]" , " --offset=OFFSET Request results from offset OFFSET [default: 0]" , " make-schema prints a simple schema for this document" ] -- ------------------------------------------------------------ -- | Initializes the loggers with the given priority. initLoggers :: Log.Priority -> IO () initLoggers level = do handlerBare <- Log.streamHandler System.stderr Log.DEBUG let handler = Log.setFormatter handlerBare $ Log.simpleLogFormatter "[$time : $loggername : $prio] $msg" Log.updateGlobalLogger "" (Log.setLevel level . Log.setHandlers [handler]) rl <- Log.getRootLogger Log.saveGlobalLogger rl data Options = Options { optLogLevel ::Log.Priority } printTime :: IO a -> IO a printTime act = do start <- getTime result <- act end <- getTime let delta = end - start Log.infoM "main" $ "took " ++ (show (delta)) return result where getTime = getPOSIXTime -- realToFrac `fmap` readDocuments :: ByteString -> IO [H.ApiDocument] readDocuments bs = maybe (do {(Log.infoM "main" $ "unable to parse ApiDocuments") ; return []}) return docs where docs = ((return <$> decode bs) <|> decode bs <|> (H.insertCmdsToDocuments <$> decode bs)) makeSchema :: FilePath -> IO String makeSchema fileName = do file <- cs <$> readFile fileName docs <- readDocuments file let cmds = H.createContextCommands docs return $ cs $ encodePretty cmds makeInserts :: FilePath -> IO String makeInserts fileName = do file <- cs <$> readFile fileName docs <- readDocuments file return $ cs $ encodePretty $ H.cmdSequence $ H.cmdInsertDoc <$> docs evalCmd :: String -> H.Command -> IO ByteString evalCmd server cmd = do encodePretty <$> HC.evalOnServer_ (cs server) cmd eval :: String -> FilePath -> IO ByteString eval server fileName = do file <- readFile fileName evalCmd server $ fromJust $ decode $ cs file search :: String -> String -> Int -> Int -> IO ByteString search server query maxResults offsetResults = cs <$> (encodePretty :: H.LimitedResult H.ApiDocument -> ByteString) <$> HC.withHuntServer (cs server) (HC.getQuery (cs query) maxResults offsetResults ) autocomplete :: String -> String -> IO String autocomplete server query = cs <$> (encodePretty :: [Text] -> ByteString) <$> (HC.withHuntServer (cs server) (HC.getAutocomplete $ cs query)) -- | Main function for the executable. main :: IO () main = do initLoggers Log.DEBUG args <- optionsWithUsage usage =<< getArgs let isCommand str = args `isPresent` (command str) fileArgument = args `getArg` (argument "") queryArgument = args `getArg` (argument "") server <- do if (args `isPresent` (longOption "server")) then args `getArg` (longOption "server") else return "http://localhost:3000" maxResults <- read <$> (args `getArg` (longOption "max")) offsetResults <- read <$> (args `getArg` (longOption "offset")) when (isCommand "eval") $ do file <- fileArgument putStr =<< (printTime $ cs <$> eval server file) when (isCommand "load") $ do file <- fileArgument putStr =<< cs <$> (evalCmd server $ H.cmdLoadIndex file) when (isCommand "store") $ do file <- fileArgument putStr =<< cs <$> (evalCmd server $ H.cmdStoreIndex file) when (isCommand "search") $ do query <- queryArgument putStr =<< (printTime $ cs <$> search server query maxResults offsetResults) when (isCommand "completion") $ do query <- queryArgument putStr =<< (printTime $ cs <$> autocomplete server query) when (isCommand "from-csv") $ do CSV.convert =<< fileArgument when (isCommand "make-schema") $ do file <- fileArgument putStr =<< makeSchema file when (isCommand "make-insert") $ do file <- fileArgument putStr =<< makeInserts file