packages feed

nmis-parser (empty) → 0.1.0.0

raw patch · 11 files changed

+558/−0 lines, 11 filesdep +Nmisdep +basedep +containersbinary-added

Dependencies added: Nmis, base, containers, megaparsec

Files

+ .DS_Store view

binary file changed (absent → 6148 bytes)

+ ._.DS_Store view

binary file changed (absent → 120 bytes)

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Author name here (c) 2017++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Author name here nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,29 @@+# NMIS file parser + - NMIS stands for Network Management Information System++This parser parses the NMIS format files to `Nmis` record type++#### Example usage :++```haskell+  module Main where+  import System.Environment (getArgs)+  import System.IO+  import Text.Megaparsec+  import Text.Nmis++  main :: IO ()+  main = do+    args <- getArgs+    case args of+      [] -> putStrLn "error: you need to pass in file path"+      [path] -> do+              contents <- readFile path+              let result = parse parseNmis "" contents+              case result of+                  Left nodes -> print $ parseErrorPretty nodes+                  Right nodes -> do+                      print nodes+      _ -> putStrLn "error: you need to pass in only one file path"++```
+ nmis-parser.cabal view
@@ -0,0 +1,40 @@+name:                nmis-parser+version:             0.1.0.0+synopsis:            NMIS file parser+homepage:            https://github.com/v0d1ch/nmis-parser#readme+license:             BSD3+license-file:        LICENSE+author:              Sasa Bogicevic+maintainer:          brutallesale@gmail.com+copyright:           2017 Sasa Bogicevic+category:            Text, Parsers+build-type:          Simple+extra-source-files:  README.md+cabal-version:       >=1.10++description:+     Parser for __NMIS__ (Network Management Information System) files to record type. Main module to use is __Text.Nmis__ and __parseNmis__ function++library+  hs-source-dirs:      src+  exposed-modules:     Text.Nmis+                     , Text.Internal.Helper+                     , Text.Internal.NmisTypes+  build-depends:       base >= 4.7 && < 5+                     , containers+                     , megaparsec+  default-language:    Haskell2010+++test-suite nmis-test+  type:                exitcode-stdio-1.0+  hs-source-dirs:      test+  main-is:             Spec.hs+  build-depends:       base+                     , Nmis+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N+  default-language:    Haskell2010++source-repository head+  type:     git+  location: https://github.com/v0d1ch/nmis-parser
+ src/Text/Internal/Helper.hs view
@@ -0,0 +1,93 @@+{-|+Module      : Text.Internal.Helper+Description : Helper for parse actions +Copyright   : (c) Sasa Bogicevic, 2017+License     : GPL-3+Maintainer  : brutallesale@gmail.com+Stability   : experimental+Uses megaparsec library +-}++{-# LANGUAGE OverloadedStrings #-}++module Text.Internal.Helper where++import Control.Applicative (empty)+import Control.Monad (void)+import Prelude hiding (until)+import Text.Megaparsec+import qualified Text.Megaparsec.Lexer as L+import Text.Megaparsec.String++-- | space consumer - consume space and comments+spaceConsumer :: Parser ()+spaceConsumer = L.space (void spaceChar) lineCmnt blockCmnt+  where+    lineCmnt = L.skipLineComment "#"+    blockCmnt = L.skipBlockComment "/*" "*/"+-- | hashbang line comment+lineComment :: Parser ()+lineComment = L.skipLineComment "#"++-- | space consumer no 2+scn :: Parser ()+scn = L.space (void spaceChar) lineComment empty++-- | lexeme+lexeme :: Parser a -> Parser a+lexeme = L.lexeme spaceConsumer++-- | symbol+symbol :: String -> Parser String+symbol = L.symbol scn++-- | arrow - parse haskell constraint like arrow sign+parrow :: Parser String+parrow = lexeme $ string " => "++-- | equals - parse equals sign+pequals :: Parser String+pequals = lexeme $ string " = "++-- | parse all between parens+parens :: Parser a -> Parser a+parens = between (string "(") (string ")")++-- | parse all between braces+braces :: Parser a -> Parser a+braces = between (string "{") (string "}")++-- | parse until string passed as function parameter+until :: String -> Parsec Dec String String+until s = anyChar `manyTill` string s++-- | parse until newline character+untilEol :: Parsec Dec String String+untilEol = anyChar `someTill` newline++-- | parse until newline character+phash :: Parser String+phash = lexeme $ string' "%hash" >> pequals++-- | parse quoted string with optional space in front of it+pQuotedStr :: Parser String+pQuotedStr = do+  _ <- optional space+  string' "'" >> until "'"++-- | parse 'undef' literal+pUndefined :: Parser String+pUndefined = do+  _ <- optional space+  string' "undef"++-- | combined parser for single record+pOpt :: Parser (String, String)+pOpt = do+  _ <- space+  key <- pQuotedStr+  _ <- space >> string "=>" >> space+  value <- try (pQuotedStr <|> pUndefined <|> many numberChar)+  _ <- optional $ string' ","+  _ <- newline+  return (key, value)
+ src/Text/Internal/Helper.hs~ view
@@ -0,0 +1,84 @@+{-# LANGUAGE OverloadedStrings #-}+-- | This helper module contains functions to parse nmis file.+-- It uses megapasec library+module Helper where++import Control.Applicative (empty)+import Control.Monad (void)+import Prelude hiding (until)+import Text.Megaparsec+import qualified Text.Megaparsec.Lexer as L+import Text.Megaparsec.String++-- | space consumer - consume space and comments+spaceConsumer :: Parser ()+spaceConsumer = L.space (void spaceChar) lineCmnt blockCmnt+  where+    lineCmnt = L.skipLineComment "#"+    blockCmnt = L.skipBlockComment "/*" "*/"+-- | hashbang line comment+lineComment :: Parser ()+lineComment = L.skipLineComment "#"++-- | space consumer no 2+scn :: Parser ()+scn = L.space (void spaceChar) lineComment empty++-- | lexeme+lexeme :: Parser a -> Parser a+lexeme = L.lexeme spaceConsumer++-- | symbol+symbol :: String -> Parser String+symbol = L.symbol scn++-- | arrow - parse haskell constraint like arrow sign+parrow :: Parser String+parrow = lexeme $ string " => "++-- | equals - parse equals sign+pequals :: Parser String+pequals = lexeme $ string " = "++-- | parse all between parens+parens :: Parser a -> Parser a+parens = between (string "(") (string ")")++-- | parse all between braces+braces :: Parser a -> Parser a+braces = between (string "{") (string "}")++-- | parse until string passed as function parameter+until :: String -> Parsec Dec String String+until s = anyChar `manyTill` string s++-- | parse until newline character+untilEol :: Parsec Dec String String+untilEol = anyChar `someTill` newline++-- | parse until newline character+phash :: Parser String+phash = lexeme $ string' "%hash" >> pequals++-- | parse quoted string with optional space in front of it+pQuotedStr :: Parser String+pQuotedStr = do+  _ <- optional space+  string' "'" >> until "'"++-- | parse 'undef' literal+pUndefined :: Parser String+pUndefined = do+  _ <- optional space+  string' "undef"++-- | combined parser for single record+pOpt :: Parser (String, String)+pOpt = do+  _ <- space+  key <- pQuotedStr+  _ <- space >> string "=>" >> space+  value <- try (pQuotedStr <|> pUndefined <|> many numberChar)+  _ <- optional $ string' ","+  _ <- newline+  return (key, value)
+ src/Text/Internal/NmisTypes.hs view
@@ -0,0 +1,44 @@+{-|+Module      : Text.Internal.NmisTypes+Description : Contains single type that holds all parsed data  +Copyright   : (c) Sasa Bogicevic, 2017+License     : GPL-3+Maintainer  : brutallesale@gmail.com+Stability   : experimental+-}+module Text.Internal.NmisTypes where++-- | Main type that holds all parsed data+data Nmis = Nmis+  { customer :: Maybe String+  , groups :: Maybe String+  , active :: Maybe String+  , advancedOptions :: Maybe String+  , authKey :: Maybe String+  , authPassword :: Maybe String+  , authProtocol :: Maybe String+  , businessService :: Maybe String+  , calls :: Maybe String+  , cbqos :: Maybe String+  , collect :: Maybe String+  , community :: Maybe String+  , depend :: Maybe String+  , display_name :: Maybe String+  , group :: Maybe String+  , host :: Maybe String+  , location :: Maybe String+  , model :: Maybe String+  , name :: Maybe String+  , netType :: Maybe String+  , ping :: Maybe String+  , port :: Maybe String+  , rancid :: Maybe String+  , roleType :: Maybe String+  , serviceStatus :: Maybe String+  , services :: Maybe String+  , threshold :: Maybe String+  , timezone :: Maybe Integer+  , uuid :: Maybe String+  , version :: Maybe String+  , webserver :: Maybe String+  } deriving (Show)
+ src/Text/Internal/NmisTypes.hs~ view
@@ -0,0 +1,36 @@+module NmisTypes where++-- | Main type that containes all parsed data+data Nmis = Nmis+  { customer :: Maybe String+  , groups :: Maybe String+  , active :: Maybe String+  , advancedOptions :: Maybe String+  , authKey :: Maybe String+  , authPassword :: Maybe String+  , authProtocol :: Maybe String+  , businessService :: Maybe String+  , calls :: Maybe String+  , cbqos :: Maybe String+  , collect :: Maybe String+  , community :: Maybe String+  , depend :: Maybe String+  , display_name :: Maybe String+  , group :: Maybe String+  , host :: Maybe String+  , location :: Maybe String+  , model :: Maybe String+  , name :: Maybe String+  , netType :: Maybe String+  , ping :: Maybe String+  , port :: Maybe String+  , rancid :: Maybe String+  , roleType :: Maybe String+  , serviceStatus :: Maybe String+  , services :: Maybe String+  , threshold :: Maybe String+  , timezone :: Maybe Integer+  , uuid :: Maybe String+  , version :: Maybe String+  , webserver :: Maybe String+  } deriving (Show)
+ src/Text/Nmis.hs view
@@ -0,0 +1,200 @@+{-|+Module      : Text.Nmis+Description : Main module for nmis parsing+Copyright   : (c) Sasa Bogicevic, 2017+License     : GPL-3+Maintainer  : brutallesale@gmail.com+Stability   : experimental++-}++--   NMIS stands for Network Management Information System+--+--   This parser parses the nmis format files to Nmis record type+--+--  Example usage :+--+--  module Main where+--+--  import System.Environment (getArgs)+--+--  import System.IO+--+--  import Text.Megaparsec+--+--  import Text.Nmis+--+--  main :: IO ()+--+--  main = do+--+--    args <- getArgs+--+--    case args of+--+--      [] -> putStrLn "error: you need to pass in file path"+--+--      [path] -> do+--+--              contents <- readFile path+--+--              let result = parse parseNmis "" contents+--+--              case result of+--+--                  Left nodes -> print $ parseErrorPretty nodes+--+--                  Right nodes -> do+--+--                      print nodes+--+--      _ -> putStrLn "error: you need to pass in only one file path"+--++{-# LANGUAGE OverloadedStrings #-}++module Text.Nmis where+++import Control.Monad (join)+import qualified Data.Map.Strict as M+import Prelude hiding (until)+import Text.Megaparsec+import Text.Megaparsec.String+import Text.Read (readMaybe)+import Data.Maybe (fromMaybe)+import Text.Internal.NmisTypes+import Text.Internal.Helper as H++-- |  Parse nmis file to [Nmis]+--+--    __This is a single function you will need to parse the file__+parseNmis :: Parser [Nmis]+parseNmis =+  lexeme $ do+    _ <- optional $ symbol "#"+    _ <- phash+    _ <- space >> string "("+    parseToList+++-- | Parses single record+parseSingle :: Parser Nmis+parseSingle = do+  _ <- optional H.pQuotedStr+  _ <- until "=>" >> space >> string "{" >> newline+  node <- manyTill pOpt (try $ lookAhead $ optional space *> string "}")+  _ <- optional space >> string "}"+  _ <- optional $ string ","+  let rmap = M.fromList node+  return+    Nmis+    { customer = M.lookup "customer" rmap+    , groups = M.lookup "groups" rmap+    , active = M.lookup "active" rmap+    , businessService = M.lookup "businessService" rmap+    , advancedOptions = M.lookup "advancedOptions" rmap+    , authKey = M.lookup "authKey" rmap+    , authPassword = M.lookup "authPassword" rmap+    , authProtocol = M.lookup "authProtocol" rmap+    , calls = M.lookup "calls" rmap+    , cbqos = M.lookup "cbqos" rmap+    , collect = M.lookup "collect" rmap+    , community = M.lookup "community" rmap+    , depend = M.lookup "depend" rmap+    , display_name = M.lookup "display_name" rmap+    , group = M.lookup "group" rmap+    , host = M.lookup "host" rmap+    , location = M.lookup "location" rmap+    , model = M.lookup "model" rmap+    , name = M.lookup "name" rmap+    , netType = M.lookup "netType" rmap+    , ping = M.lookup "ping" rmap+    , port = M.lookup "port" rmap+    , rancid = M.lookup "rancid" rmap+    , roleType = M.lookup "roleType" rmap+    , serviceStatus = M.lookup "serviceStatus" rmap+    , services = M.lookup "services" rmap+    , threshold = M.lookup "threshold" rmap+    , timezone = join $ readMaybe <$> M.lookup "timezone" rmap+    , uuid = M.lookup "uuid" rmap+    , version = M.lookup "version" rmap+    , webserver = M.lookup "webserver" rmap+    }+++-- |+-- This function is used to match records by group/groups field.+--+-- You have two lists with Nmis types [Nmis] [Nmis]+--+-- and you want to match group field from one to the groups field from the other,+--+-- grab a customer field from first list and attach it to the second list which you can save later.+--+-- This is something of practical use which I needed in the real world.+lookupInList :: [Nmis] ->  Nmis -> Nmis+lookupInList cust n = do+   let fcusts =  filterByGroup (group n) cust+   if length fcusts > 0 then+       n { customer = customer (head fcusts) }+   else n++-- | Filters Nmis by Nodes group+filterByGroup :: Maybe String -> [Nmis]  -> [Nmis]+filterByGroup s cl = filter (\c -> groups c == s) cl++-- | parses many single values until ');'+parseToList :: Parser [Nmis]+parseToList = do+  result <-+    manyTill parseSingle (try $ lookAhead $ optional space >> string ")")+  _ <- optional newline+  _ <- string ")"+  _ <- optional $ string ";"+  return result++-- | Show maybe integer for timezone field+showMaybeInt :: Maybe Integer -> String+showMaybeInt i = case i of+  Nothing -> ""+  Just x -> show x++-- | Show Nmis list+--+-- Use for printing the [Nmis] list+showNmis :: [Nmis] -> String+showNmis [] =  ""+showNmis (c:cx) =+  "\n  '" ++ fromMaybe "" (name c) ++ "' => {\n"+  ++ "    'customer' => '" ++ fromMaybe ""  (customer c) ++ "',\n"+  ++ "    'active' => '" ++ fromMaybe ""  (active c) ++ "',\n"+  ++ "    'authkey' => '" ++ fromMaybe ""  (authKey c) ++ "',\n"+  ++ "    'authpassword' => '" ++ fromMaybe ""  (authPassword c) ++ "',\n"+  ++ "    'authprotocol' => '" ++ fromMaybe ""  (authProtocol c) ++ "',\n"+  ++ "    'businesService' => '" ++ fromMaybe "" (businessService c) ++ "',\n"+  ++ "    'calls' => '" ++ fromMaybe ""  (calls c) ++ "',\n"+  ++ "    'cbqos' => '" ++ fromMaybe ""  (cbqos c) ++ "',\n"+  ++ "    'collect' => '" ++ fromMaybe ""  (collect c) ++ "',\n"+  ++ "    'community' => '" ++ fromMaybe ""  (community c) ++ "',\n"+  ++ "    'depend' => '" ++ fromMaybe ""  (depend c) ++ "',\n"+  ++ "    'display_name' => '" ++ fromMaybe "" (display_name c) ++ "',\n"+  ++ "    'group' => '" ++ fromMaybe ""  (group c) ++ "',\n"+  ++ "    'host' => '" ++ fromMaybe ""  (host c) ++ "',\n"+  ++ "    'location' => '" ++ fromMaybe ""  (location c) ++ "',\n"+  ++ "    'model' => '" ++ fromMaybe ""  (model c) ++ "',\n"+  ++ "    'name' => '" ++ fromMaybe ""  (name c) ++ "',\n"+  ++ "    'netType' => '" ++ fromMaybe ""  (netType c) ++ "',\n"+  ++ "    'ping' => '" ++ fromMaybe ""  (ping c) ++ "',\n"+  ++ "    'port' => '" ++ fromMaybe ""  (port c) ++ "',\n"+  ++ "    'rancid' => '" ++ fromMaybe ""  (rancid c) ++ "',\n"+  ++ "    'roleType' => '" ++ fromMaybe ""  (roleType c) ++ "',\n"+  ++ "    'serviceStatus' => '" ++ fromMaybe ""  (serviceStatus c) ++ "',\n"+  ++ "    'services' => '" ++ fromMaybe ""  (services c) ++ "',\n"+  ++ "    'threshold' => '" ++ fromMaybe ""  (threshold c) ++ "',\n"+  ++ "    'timezone' => '" ++ showMaybeInt (timezone c) ++ "',\n"+  ++ "    'uuid' => '" ++ fromMaybe ""  (uuid c) ++ "',\n"+  ++ "    'version' => '" ++ fromMaybe ""  (version c) ++ "',\n"+  ++ "    'webserver' => '" ++ fromMaybe ""  (webserver c) ++ "',\n"+  ++ "},"+  ++ showNmis cx
+ test/Spec.hs view
@@ -0,0 +1,2 @@+main :: IO ()+main = putStrLn "Test suite not yet implemented"