packages feed

ldif 0.0.3 → 0.0.4

raw patch · 6 files changed

+135/−21 lines, 6 filesdep +containersnew-component:exe:ldif2html

Dependencies added: containers

Files

TODO.org view
@@ -11,3 +11,12 @@ * TODO add module tests for versioned LDIFs * TODO add module tests for base64 parsing * TODO Implement Attribute Name case-insensitive matching at DN+* TODO Use getopt for input parameters on diffLDIF cmd+* TODO Implement ldifmodify (like ldapmodify)+   offline applying of Change LDIF on Content LDIF+   ldifmodify -h <contentLDIF> -f <changeLDIF> [-o <contentLDIFAfter>] +* DONE Change interface for providing parser method with expected type of LDIF+it allows parse changeldif as contentldif regardless the content.++* DONE Add ldif2html which generate hypertext LDIF representation+* DONE Update unwrap method in preprocessor for feasible resource consuption
ldif.cabal view
@@ -1,5 +1,5 @@ Name:            ldif-Version:         0.0.3+Version:         0.0.4 License:         BSD3 License-File:    LICENSE Synopsis:        The LDAP Data Interchange Format (LDIF) parser @@ -15,7 +15,9 @@  It includes following tool:  .  - diffLDIF command generates change LDIF between two -   content LDIF files. +   content LDIF files.+ - ldif2html command generates hypertext HTML browsable+   LDIF file.   . Category:        Text Stability:       experimental@@ -39,7 +41,7 @@      Source-Repository head   type:     darcs-  location: http://rampa.sk/repo/ldif+  location: http://patch-tag.com/r/dixiecko/ldif  flag test   description: Build test program.@@ -50,6 +52,7 @@                    base         < 5,                    filepath,                    haskell98,+                   containers,                    parsec       >= 2.1.0,                    Cabal        >= 1.5 && < 1.9   Hs-Source-Dirs:  src@@ -66,6 +69,10 @@ Executable diffLDIF   Hs-Source-Dirs:  src   Main-Is:         diffLDIF.hs++Executable ldif2html+  Hs-Source-Dirs:  src+  Main-Is:         ldif2html.hs  Executable test   Hs-Source-Dirs:  src, tests
src/Text/LDIF/Parser.hs view
@@ -1,5 +1,6 @@ module Text.LDIF.Parser ( 	parseLDIFStr,+        parseLDIFStrAs, 	parseLDIFFile,         parseDNStr )@@ -8,25 +9,36 @@ import Text.ParserCombinators.Parsec import Data.Either import Data.Char-import Data.List (isPrefixOf)+import Data.List (isPrefixOf, foldl')  -- | Parse string as LDIF content and return LDIF or ParseError parseLDIFStr :: String -> Either ParseError LDIF-parseLDIFStr = parse pLdif "(param)" . preproc +parseLDIFStr = parseLDIFStrAs Nothing   -- | Read and parse provided file and return LDIF or ParseError parseLDIFFile :: String -> IO (Either ParseError LDIF) parseLDIFFile name = do 	input <- readFile name-	return $ parse pLdif name (preproc input)+        return $ parseLDIFStrAs' name Nothing input +-- | Read and parse provided string and return LDIF or ParserError+-- | If LDIF type is specified than given type is expected for parsing +-- | and mismatch generates ParseError+parseLDIFStrAs' :: String -> Maybe LDIFType -> String -> Either ParseError LDIF+parseLDIFStrAs' nm Nothing                = parse pLdif        nm . preproc+parseLDIFStrAs' nm (Just LDIFContentType) = parse pLdifContent nm . preproc+parseLDIFStrAs' nm (Just LDIFChangesType) = parse pLdifChanges nm . preproc++parseLDIFStrAs :: Maybe LDIFType -> String -> Either ParseError LDIF+parseLDIFStrAs = parseLDIFStrAs' "(param)"+ -- | Parse string as DN and return DN type or ParseError parseDNStr :: String -> Either ParseError DN parseDNStr = parse pDN "(param)"   -- | Preprocessing for concat wrapped lines and remove comment lines preproc :: String -> String-preproc = unwrap . stripComments+preproc = stripComments . unwrap  -- | Remove Comment Lines stripComments :: String -> String@@ -34,32 +46,36 @@  -- | Unwrap lines, lines with space at begin is continue of previous line  unwrap :: String -> String-unwrap input = unlines $ preprocLines $ lines input-   where -    preprocLines xs = unbox $ foldl (preprocLine) ([],Nothing) xs-    preprocLine (ys,r) []                 = (addLineMaybe ys r,Just []) -    preprocLine (ys,r) (l:lx) | l == ' '  = (ys,concatLineMaybe r lx)-                              | otherwise = (addLineMaybe ys r, Just $ l:lx)-    concatLineMaybe Nothing  x = Just x-    concatLineMaybe (Just y) x = Just (y++x)-    addLineMaybe xs Nothing  = xs-    addLineMaybe xs (Just x) = xs++[x]-    unbox (ys,Nothing) = ys-    unbox (ys,Just x)  = ys++[x]+unwrap xs = unlines $ takeLines $ lines xs +takeLines :: [String] -> [String]+takeLines [] = []+takeLines xs = let (ln,ys) = takeLine xs+               in ln:takeLines ys++takeLine :: [String] -> (String, [String])+takeLine []     = ([],[])+takeLine (x:[]) = (x,[])+takeLine (x:xs) = let isCont x = " " `isPrefixOf` x  +                  in (x ++ (concat $ map (tail) $ takeWhile (isCont) xs), dropWhile (isCont) xs) + -- | Parsec ldif parser pLdif :: CharParser st LDIF pLdif = try pLdifChanges <|> pLdifContent  pLdifChanges :: CharParser st LDIF pLdifChanges = do+    pSEPs     ver <- optionMaybe pVersionSpec+    pSEPs     recs <- sepEndBy1 pChangeRec pSEPs     return $ LDIFChanges ver recs  pLdifContent :: CharParser st LDIF pLdifContent = do+    pSEPs     ver <- optionMaybe pVersionSpec+    pSEPs     recs <- sepEndBy1 pAttrValRec pSEPs     return $ LDIFContent ver recs 
src/Text/LDIF/Proc.hs view
@@ -34,7 +34,7 @@ -- | 1. Iterate over L1 DN's and Modify / Remove Content  -- | 2. Iterate over L2 and Add Content not in L1 diffLDIF :: LDIF -> LDIF -> Maybe LDIF-diffLDIF l1@(LDIFContent v1 c1) l2@(LDIFContent v2 c2) = Just (LDIFChanges v2 changes) +diffLDIF (LDIFContent _ c1) l2@(LDIFContent v2 _) = Just (LDIFChanges v2 changes)     where        changes = filter (not . isDummyChangeRecord) $ foldl (processEntry) [] c1       processEntry xs e1 = let me2 = findContentByDN l2 (coDN e1) 
src/Text/LDIF/Types.hs view
@@ -6,14 +6,17 @@         Change(..),         Modify(..),          DN(..), +        LDIFType(..),         Attribute, Value, AttrValue ) where-import Data.Char  type Attribute = String type Value = String type AttrValue = (Attribute, Value)++-- | Type of LDIF Files (Content, Changes)+data LDIFType = LDIFContentType | LDIFChangesType deriving (Show, Eq) -- Maybe LDIFMixedType   -- | Represents LDIF structure, it can be either simply LDIF data dump or -- | changes LDIF with LDAP operations 
+ src/ldif2html.hs view
@@ -0,0 +1,79 @@+-- | Make Change LDIF based on two Content LDIFs+import Data.List+import Data.Either+import Data.Maybe+import Control.Monad +import System.FilePath +import System.Environment+import Text.LDIF+import qualified Data.Set as Set++ldif2html :: Set.Set String -> LDIF -> String+ldif2html idx (LDIFContent v xs) = unlines $ (ver2Str v) ++ (map (content2html idx) xs)+ldif2html idx (LDIFChanges v xs) = unlines $ (ver2Str v) ++ (map (change2html idx) xs)++-- | Serialize version to LDIF Format Lines+ver2Str :: Maybe String -> [String]+ver2Str Nothing = []+ver2Str (Just v) = ["version: "++v]++-- | Serialize DN to LDIF Format+dn2html :: DN -> String+dn2html ys@(DN xs) = concat [ "<div id=\"abc"++nm++"\"></div><b>dn:</b> <font color=\"green\"><b>", intercalate "," $ map (\(n,v) -> n++"="++v) xs, "</b></font>"]+      where+         nm = dn2last ys++dn2last (DN xs) = snd $ head xs++-- | Serialize Content Record in LDIF Format+content2html :: Set.Set String -> ContentRecord -> String+content2html idx (ContentRecord dn xs) = unlines $ [ (dn2html dn) ] ++ (attrVals2Ln idx xs)++-- | Serialize Change Record in LDIF Format+change2html :: Set.Set String -> ChangeRecord -> String+change2html idx (ChangeRecord dn (ChangeDelete))     = unlines   [ (dn2Str dn), "changetype: delete" ]+change2html idx (ChangeRecord dn (ChangeAdd xs))    = unlines $ [ (dn2html dn), "changetype: add"    ] ++ (attrVals2Ln idx xs)+change2html idx (ChangeRecord dn (ChangeModify xs))  = unlines $ [ (dn2Str dn), "changetype: modify" ] ++ (mods2Ln idx xs)+change2html idx (ChangeRecord dn (ChangeModDN))      = unlines $ [ (dn2Str dn), "changetype: moddn"  ]++attrVals2Ln :: Set.Set String -> [AttrValue] -> [String]+attrVals2Ln idx xs = map (attrVal2Ln idx) xs++attrVal2Ln :: Set.Set String -> AttrValue -> String+attrVal2Ln idx (n,v) = if Set.member v idx then "<b>"++n++"</b> : <a href=\"#abc"++v++"\">"++v++"</a>"+                          else "<b>"++n++"</b> : "++v++mods2Ln :: Set.Set String -> [Modify] -> [String]+mods2Ln idx xs = intercalate ["-"] $ map (mod2Ln idx) xs++mod2Ln :: Set.Set String -> Modify -> [String]+mod2Ln idx (ModAdd     nm xs) = [ attrVal2Ln idx ("add",nm)     ] ++ (map (\v -> attrVal2Ln idx (nm,v)) xs) +mod2Ln idx (ModDelete  nm xs) = [ attrVal2Ln idx ("delete",nm)  ] ++ (map (\v -> attrVal2Ln idx (nm,v)) xs)+mod2Ln idx (ModReplace nm xs) = [ attrVal2Ln idx ("replace",nm) ] ++ (map (\v -> attrVal2Ln idx (nm,v)) xs)++-- Dummy ldif2html implementation but it should+-- display LDIF file as HTML with values as href to+-- DN which has the value as the leaf RDN value+main = do+  args <- getArgs+  case args of +     []         -> putStrLn "Usage: ldif2html <input.ldif> [<input2.ldif> <input3.ldif> ... <inputN.ldif> <output.ldif>]"+     [inp]      -> do+                      doLDIF2HTML [inp] (putStrLn)+                      putStrLn "# Done."+     xs         -> do+                      doLDIF2HTML (init xs) (writeFile (last xs)) +                      putStrLn $ "## Processed : " ++ (unlines $ init xs)+                      putStrLn $ "## Written   : " ++ (last xs)++doLDIF2HTML names outF = do+  mls <- mapM (parseLDIFFile) names+  case lefts mls of +       []   -> do+                 let idx = Set.unions $ map (dns) (rights mls)+                 outF $ concat ["<html><body bgcolor=lightyellow><pre>", concat $ map (ldif2html idx) (rights mls), "</pre></body></html>" ]+       xs  -> mapM_ print xs++dns :: LDIF -> Set.Set String+dns (LDIFContent _ xs) = Set.fromList $ nub $ map (dn2last . coDN) xs+dns (LDIFChanges _ xs) = Set.fromList $ nub $ map (dn2last . chDN) xs