{-# Language OverloadedStrings, ScopedTypeVariables #-} -------------------------------------------------------------------- -- | -- Module : Utils.Katt.Init -- -- Init submodule providing initialization of problems -- and entire problem sessions. -- -- Problems are initialized by creating a directory, configuration file, -- and optionally downloading all test files available. -- Both zip-based test data and embedded HTML tables are supported. -- -- Problem sessions are initialized by parsing the list of problems and -- initializing each problem separately. module Utils.Katt.Init (initializeProblem, initializeSession) where import Control.Applicative ((<$>), (<*)) import qualified Codec.Archive.Zip as Z import Control.Arrow ((***)) import Control.Monad (liftM, liftM2, void, when) import qualified Control.Monad.State as S import Control.Error hiding (tryIO) import qualified Control.Exception as E import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy.Char8 as BL import Data.Foldable (fold) import Data.List (isSuffixOf, nub) import Data.Monoid ((<>)) import qualified System.Directory as D import System.IO (stderr) import Text.Parsec hiding (token) import Text.Parsec.ByteString import qualified Utils.Katt.Configuration as C import Utils.Katt.Utils -- | Parsed test cases associated with a problem. type TestContent = [(B.ByteString, B.ByteString)] -- | Possible test case scenarios. data TestParser -- | No tests available. = NoTestsAvailable -- | Test content available in zip file, given as URL. | TestAddress B.ByteString -- | Embedded test content. | TestContents TestContent deriving Show -- | Parse the possible different test file cases, given the problem page. -- Any zip download links are preferred over embedded test data. parseProblemPage :: B.ByteString -> TestParser parseProblemPage contents = case res of Left _ -> NoTestsAvailable Right test -> test where res = parse (try parseAddress <|> parseEmbedded) "Test parser" contents -- | Try to parse a download URL from the supplied page data. parseAddress :: GenParser Char st TestParser parseAddress = do void $ manyTill anyChar (try $ startLink >> lookAhead endParser) TestAddress . B.cons '/' . B.pack <$> endParser where startLink = string " tests where sp = skipMany $ space <|> newline <|> tab beginTag tag = void $ char '<' >> sp >> string tag >> sp >> char '>' endTag tag = void $ char '<' >> sp >> char '/' >> string tag >> sp >> char '>' htmlTag tag p = do sp >> beginTag tag >> sp manyTill p $ try $ endTag tag tr = htmlTag "tr" td = htmlTag "td" pre = htmlTag "pre" tests = manyTill anyChar (lookAhead startTable) >> endBy1 testTable sp startTable = void . try $ string "