module Nix.JenkinsPlugins2Nix.Parser
( parseManifest
, runParseManifest
) where
import Control.Applicative
import Control.Monad (void)
import qualified Data.Attoparsec.Text as A
import Data.Either (either)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Monoid ((<>))
import Data.Set (Set)
import qualified Data.Set as Set
import Data.Text (Text)
import qualified Data.Text as Text
import Nix.JenkinsPlugins2Nix.Types
runParseManifest :: Text -> Either String Manifest
runParseManifest = A.parseOnly parseManifest
parseManifest :: A.Parser Manifest
parseManifest = do
kvs <- kvMap
let getKey :: Text -> Either String Text
getKey k = case Map.lookup k kvs of
Nothing -> Left $ "Could not find " <> Text.unpack k <> " in " <> show kvs
Just v -> Right v
getKeyParsing :: Text -> A.Parser a -> Either String a
getKeyParsing k p = getKey k >>= A.parseOnly p
eManifest :: Either String Manifest
eManifest = do
manifest_version' <- getKey "Manifest-Version"
archiver_version' <- optional $ getKey "Archiver-Version"
created_by' <- optional $ getKey "Created-By"
built_by' <- optional $ getKey "Built-By"
build_jdk' <- optional $ getKey "Build-Jdk"
extension_name' <- optional $ getKey "Extension-Name"
specification_title' <- optional $ getKey "Specification-Title"
implementation_title' <- optional $ getKey "Implementation-Title"
implementation_version' <- optional $ getKey "Implementation-Version"
group_id' <- optional $ getKey "Group-Id"
short_name' <- getKey "Short-Name"
long_name' <- getKey "Long-Name"
url' <- getKey "Url"
plugin_version' <- getKey "Plugin-Version"
hudson_version' <- optional $ getKey "Hudson-Version"
jenkins_version' <- optional $ getKey "Jenkins-Version"
plugin_dependencies' <- either (\_ -> Right Set.empty) return $
getKeyParsing "Plugin-Dependencies" parsePluginDependencies
plugin_developers' <- either (\_ -> Right Set.empty) return $
getKeyParsing "Plugin-Developers" parsePluginDevelopers
return $! Manifest
{ manifest_version = manifest_version'
, archiver_version = archiver_version'
, created_by = created_by'
, built_by = built_by'
, build_jdk = build_jdk'
, extension_name = extension_name'
, specification_title = specification_title'
, implementation_title = implementation_title'
, implementation_version = implementation_version'
, group_id = group_id'
, short_name = short_name'
, long_name = long_name'
, url = url'
, plugin_version = plugin_version'
, hudson_version = hudson_version'
, jenkins_version = jenkins_version'
, plugin_dependencies = plugin_dependencies'
, plugin_developers = plugin_developers'
}
case eManifest of
Left err -> fail err
Right m -> return m
where
parsePluginDevelopers :: A.Parser (Set Text)
parsePluginDevelopers = Set.fromList . Text.splitOn "," <$> A.takeText
parsePluginDependencies :: A.Parser (Set PluginDependency)
parsePluginDependencies =
let plugin = do
name <- A.takeWhile1 (/= ':') <* A.char ':'
version <- A.takeWhile1 (\c -> c /= ',' && c /= ';')
resolution <- A.peekChar >>= \case
Nothing -> return Mandatory
Just ',' -> A.char ',' *> return Mandatory
Just ';' -> do
_ <- A.string ";resolution:="
A.takeWhile1 (/= ',') >>= \case
"optional" -> return Optional
res' -> fail $ "Don't know how to parse resolution: " <> Text.unpack res'
Just c -> fail $ "plugin: expected , or ; but got: " <> [c]
void (A.char ',') <|> return ()
return $! PluginDependency
{ plugin_dependency_name = name
, plugin_dependency_version = version
, plugin_dependency_resolution = resolution
}
in Set.fromList <$> many plugin
kvEntry :: A.Parser (Text, Text)
kvEntry = do
key <- A.takeWhile1 (/= ':')
A.anyChar *> A.skipSpace
let restOfLine = A.takeTill A.isEndOfLine <* (A.endOfLine <|> return ())
indentedLine = A.peekChar' >>= \case
' ' -> A.skipSpace *> restOfLine
_ -> fail "indentedLine doesn't start with a space"
valueLines <- (:) <$> restOfLine <*> many indentedLine
return $! (key, Text.concat valueLines)
kvMap :: A.Parser (Map Text Text)
kvMap = Map.fromList <$> many kvEntry