ldif 0.0.12 → 0.0.13
raw patch · 11 files changed
+247/−224 lines, 11 filesdep +ldifPVP ok
version bump matches the API change (PVP)
Dependencies added: ldif
API changes (from Hackage documentation)
Files
- cmd/ldif2html.hs +88/−0
- cmd/ldifdiff.hs +34/−0
- cmd/ldifmodify.hs +42/−0
- cmd/ldifparse.hs +17/−0
- cmd/ldifundo.hs +36/−0
- ldif.cabal +30/−7
- src/ldif2html.hs +0/−88
- src/ldifdiff.hs +0/−34
- src/ldifmodify.hs +0/−42
- src/ldifparse.hs +0/−17
- src/ldifundo.hs +0/−36
+ cmd/ldif2html.hs view
@@ -0,0 +1,88 @@+{-# LANGUAGE BangPatterns, OverloadedStrings #-}+-- | 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+import qualified Data.ByteString.Char8 as BC++-- | Serialize DN to LDIF Format+dn2html :: DN -> BC.ByteString+dn2html ys@(DN xs) = BC.concat [ "<div id=\"abc" + , nm + , "\"></div><b>dn:</b> <font color=\"green\"><b>" + , dnstr + , "</b></font>" ]+ where+ dnstr = BC.intercalate "," $ map (\((Attribute n),v) -> n `BC.append` "=" `BC.append` (aVal v)) xs+ nm = aVal $ dn2last ys++-- | Serialize Change Record in LDIF Format+record2html :: Set.Set Value -> LDIFRecord -> BC.ByteString+record2html idx (ChangeRecord dn (ChangeDelete)) = BC.unlines [ (dn2str dn), "changetype: delete" ]+record2html idx (ChangeRecord dn (ChangeAdd xs)) = BC.unlines $ [ (dn2html dn), "changetype: add" ] ++ (attrVals2Ln idx xs)+record2html idx (ChangeRecord dn (ChangeModify xs)) = BC.unlines $ [ (dn2str dn), "changetype: modify" ] ++ (mods2Ln idx xs)+record2html idx (ChangeRecord dn (ChangeModDN)) = BC.unlines $ [ (dn2str dn), "changetype: moddn" ]+record2html idx (ContentRecord dn xs) = BC.unlines $ [ (dn2html dn) ] ++ (attrVals2Ln idx xs)++attrVals2Ln :: Set.Set Value -> [AttrValue] -> [BC.ByteString]+attrVals2Ln idx xs = map (attrVal2Ln idx) xs++attrVal2Ln :: Set.Set Value -> AttrValue -> BC.ByteString+attrVal2Ln idx ((Attribute n),v) = if Set.member v idx then BC.concat [ "<b>"+ , n + , "</b> : <a href=\"#abc"+ , aVal v+ , "\">" + , aVal v+ , "</a>"]+ else BC.concat [ "<b>",n,"</b> : ",aVal v]++mods2Ln :: Set.Set Value -> [Modify] -> [BC.ByteString]+mods2Ln idx xs = intercalate ["-"] $ map (mod2Ln idx) xs++mod2Ln :: Set.Set Value -> Modify -> [BC.ByteString]+mod2Ln idx mod = [ attrVal2Ln idx (modName,attrName) ] ++ valLst+ where+ attrName = Value $ aName $ modAttr mod+ valLst = map (\v -> attrVal2Ln idx (modAttr mod,v)) $ modAttrVals mod+ modName = case mod of + (ModAdd _ _) -> Attribute "add"+ (ModDelete _ _) -> Attribute "delete"+ (ModReplace _ _) -> Attribute "replace"++dns :: LDIF -> Set.Set Value+dns (LDIF _ xs) = Set.fromList $ nub $ map (dn2last . reDN) xs++dn2last (DN xs) = snd $ head xs++main = do+ args <- getArgs+ case args of + [] -> putStrLn "Usage: ldif2html <input.ldif> [<input2.ldif> <input3.ldif> ... <inputN.ldif> <output.ldif>]"+ [inp] -> do+ doLDIF2HTML [inp] (BC.putStrLn)+ putStrLn "# Done."+ xs -> do+ doLDIF2HTML (init xs) (BC.writeFile (last xs)) + putStrLn $ "## Processed : " ++ (unlines $ init xs)+ putStrLn $ "## Written : " ++ (last xs)+ where+ doLDIF2HTML names outF = do+ mls <- mapM (parseLDIFFile defaulLDIFConf) names+ case lefts mls of + [] -> do+ let idx = Set.unions $ map dns $ rights mls+ outF $ BC.concat [ "<html><body bgcolor=lightyellow><pre>"+ , BC.concat $ map (ldif2html idx) (rights mls) + , "</pre></body></html>" ]+ xs -> mapM_ print xs+ -- | Serialize LDIF to HTML+ ldif2html :: Set.Set Value -> LDIF -> BC.ByteString+ ldif2html idx (LDIF v xs) = BC.unlines $ (ver2str v) ++ (map (record2html idx) xs)++
+ cmd/ldifdiff.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE DeriveDataTypeable #-}+-- | 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 System.Console.CmdArgs+import qualified Data.ByteString.Char8 as BC++progDesc = "Create delta LDIF between Source LDIF and Target LDIF"++data LdifDiff = LdifDiff { srcFile :: FilePath+ , dstFile :: FilePath } deriving (Show, Data, Typeable)++defaultCfg = LdifDiff { srcFile = def &= typFile &= name "s" &= help "Source LDIF File"+ , dstFile = def &= typFile &= name "t" &= help "Target LDIF File" }++main = do+ cfg <- cmdArgs defaultCfg+ execute cfg++execute (LdifDiff [] _ ) = putStrLn "Error: -s source file is mandatory" +execute (LdifDiff _ [] ) = putStrLn "Error: -t target file is mandatory"+execute (LdifDiff src dst) = do+ ml1 <- parseLDIFFile defaulLDIFConf src+ ml2 <- parseLDIFFile defaulLDIFConf dst+ case rights [ml1,ml2] of + [l1,l2] -> case diffLDIF l1 l2 of+ Left err -> putStrLn err+ Right delta -> BC.putStrLn $ ldif2str delta+ _ -> print $ lefts [ml1,ml2]
+ cmd/ldifmodify.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE DeriveDataTypeable, OverloadedStrings #-}+-- | Apply LDAP operations within LDIF on another LDIF.+-- | Without schema related verification like syntax, cardinality etc.+import Data.List+import Data.Either+import Data.Maybe+import Control.Monad +import System.FilePath +import System.Environment+import Text.LDIF+import System.Console.CmdArgs+import qualified Data.ByteString.Char8 as BC++progDesc = "Apply LDAP operations from LDIF to LDIF (like ldapmodify)"++data LdifModify = LdifModify { baseFile :: FilePath+ , modFiles :: [FilePath]+ , outFile :: FilePath } deriving (Show, Data, Typeable)++defaultCfg = LdifModify { baseFile = def &= typFile &= name "f" &= help "Base LDIF File"+ , modFiles = def &= args &= typ "LDIF Files for applying"+ , outFile = def &= typFile &= name "o" &= help "Output LDIF File" }++main = do+ cfg <- cmdArgs defaultCfg+ execute cfg++execute (LdifModify [] _ _) = putStrLn "Error: -f base LDIF File is mandatory"+execute (LdifModify _ [] _) = putStrLn "Error: no LDIF Files for applying provided"+execute (LdifModify _ _ []) = putStrLn "Error: -o output LDIF File is mandatory"+execute cfg = do+ baseLDIF <- safeParseLDIFFile (baseFile cfg)+ modLDIFs <- mapM (safeParseLDIFFile) (modFiles cfg)+ let outLDIF = foldr (flip applyLDIF) baseLDIF modLDIFs+ if length (outFile cfg) == 0 then do+ BC.putStrLn (ldif2str outLDIF)+ else do+ BC.writeFile (outFile cfg) (ldif2str outLDIF)+ putStrLn $ (outFile cfg) ++ " written."++safeParseLDIFFile :: FilePath -> IO LDIF+safeParseLDIFFile name = liftM (either (\e -> error $ "Can not parse: "++(show e)) (id)) (parseLDIFFile defaulLDIFConf name)
+ cmd/ldifparse.hs view
@@ -0,0 +1,17 @@+-- | 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.ByteString.Char8 as BC++main = do+ args <- getArgs+ let name = args !! 0+ ml1 <- parseLDIFFile defaulLDIFConf name+ case ml1 of + Right l1 -> BC.putStrLn $ ldif2str l1+ Left err -> print err
+ cmd/ldifundo.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE DeriveDataTypeable, OverloadedStrings #-}+import Data.List+import Data.Either+import Data.Maybe+import Control.Monad+import System.FilePath+import System.Environment+import Text.LDIF+import System.Console.CmdArgs+import qualified Data.ByteString.Char8 as BC++progDesc = "Calculate undo LDIF (rollback LDIF)"++data LdifUndo = LdifUndo { inFile :: FilePath+ , outFile :: FilePath } deriving (Show, Data, Typeable)++defaultCfg = LdifUndo { inFile = def &= typFile &= name "f" &= help "Input LDIF File"+ , outFile = def &= typFile &= name "o" &= help "Output LDIF File" }++main = do+ cfg <- cmdArgs defaultCfg+ execute cfg++execute (LdifUndo [] _) = putStrLn "Error: -f base LDIF File is mandatory"+execute cfg = do+ inLDIF <- safeParseLDIFFile (inFile cfg)+ let (outLDIF, wrn) = undoLDIF inLDIF+ when (not $ null wrn) (putStrLn $ "Finished with warnings: " ++ (unlines $ map unlines wrn))+ if length (outFile cfg) == 0 then do+ BC.putStrLn (ldif2str outLDIF)+ else do+ BC.writeFile (outFile cfg) (ldif2str outLDIF)+ putStrLn $ (outFile cfg) ++ " written."++safeParseLDIFFile :: FilePath -> IO LDIF+safeParseLDIFFile name = liftM (either (\e -> error $ "Can not parse: "++(show e)) (id)) (parseLDIFFile defaulLDIFConf name)
ldif.cabal view
@@ -1,5 +1,5 @@ Name: ldif-Version: 0.0.12+Version: 0.0.13 License: BSD3 License-File: LICENSE Synopsis: The LDAP Data Interchange Format (LDIF) tools @@ -20,6 +20,8 @@ . - ldifmodify - replays delta LDIF operations on content LDIF (similar to ldapmodify). .+ - ldifundo - produces delta LDIF which rollbacks operations in input LDIF.+ . Category: Text Stability: experimental Build-Type: Simple@@ -50,7 +52,7 @@ flag cmd description: Build command line programs.- default: False+ default: True Library Build-Depends: base < 5,@@ -79,7 +81,12 @@ Text.LDIF.Undo Executable ldifdiff- Hs-Source-Dirs: src+ Hs-Source-Dirs: cmd+ Build-Depends: base < 5,+ ldif,+ cmdargs,+ filepath,+ bytestring Main-Is: ldifdiff.hs if flag(cmd) Buildable: True@@ -89,7 +96,13 @@ Buildable: False Executable ldif2html- Hs-Source-Dirs: src+ Hs-Source-Dirs: cmd+ Build-Depends: base < 5,+ ldif,+ containers,+ cmdargs,+ filepath,+ bytestring Main-Is: ldif2html.hs if flag(cmd) Buildable: True@@ -99,7 +112,12 @@ Buildable: False Executable ldifmodify- Hs-Source-Dirs: src+ Hs-Source-Dirs: cmd+ Build-Depends: base < 5,+ ldif,+ cmdargs,+ filepath,+ bytestring Main-Is: ldifmodify.hs if flag(cmd) Buildable: True@@ -109,7 +127,12 @@ Buildable: False Executable ldifundo- Hs-Source-Dirs: src+ Hs-Source-Dirs: cmd+ Build-Depends: base < 5,+ ldif,+ cmdargs,+ filepath,+ bytestring Main-Is: ldifundo.hs if flag(cmd) Buildable: True@@ -119,7 +142,7 @@ Buildable: False Executable ldifparse- Hs-Source-Dirs: src+ Hs-Source-Dirs: cmd Main-Is: ldifparse.hs if !flag(test) Buildable: False
− src/ldif2html.hs
@@ -1,88 +0,0 @@-{-# LANGUAGE BangPatterns, OverloadedStrings #-}--- | 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-import qualified Data.ByteString.Char8 as BC---- | Serialize DN to LDIF Format-dn2html :: DN -> BC.ByteString-dn2html ys@(DN xs) = BC.concat [ "<div id=\"abc" - , nm - , "\"></div><b>dn:</b> <font color=\"green\"><b>" - , dnstr - , "</b></font>" ]- where- dnstr = BC.intercalate "," $ map (\((Attribute n),v) -> n `BC.append` "=" `BC.append` (aVal v)) xs- nm = aVal $ dn2last ys---- | Serialize Change Record in LDIF Format-record2html :: Set.Set Value -> LDIFRecord -> BC.ByteString-record2html idx (ChangeRecord dn (ChangeDelete)) = BC.unlines [ (dn2str dn), "changetype: delete" ]-record2html idx (ChangeRecord dn (ChangeAdd xs)) = BC.unlines $ [ (dn2html dn), "changetype: add" ] ++ (attrVals2Ln idx xs)-record2html idx (ChangeRecord dn (ChangeModify xs)) = BC.unlines $ [ (dn2str dn), "changetype: modify" ] ++ (mods2Ln idx xs)-record2html idx (ChangeRecord dn (ChangeModDN)) = BC.unlines $ [ (dn2str dn), "changetype: moddn" ]-record2html idx (ContentRecord dn xs) = BC.unlines $ [ (dn2html dn) ] ++ (attrVals2Ln idx xs)--attrVals2Ln :: Set.Set Value -> [AttrValue] -> [BC.ByteString]-attrVals2Ln idx xs = map (attrVal2Ln idx) xs--attrVal2Ln :: Set.Set Value -> AttrValue -> BC.ByteString-attrVal2Ln idx ((Attribute n),v) = if Set.member v idx then BC.concat [ "<b>"- , n - , "</b> : <a href=\"#abc"- , aVal v- , "\">" - , aVal v- , "</a>"]- else BC.concat [ "<b>",n,"</b> : ",aVal v]--mods2Ln :: Set.Set Value -> [Modify] -> [BC.ByteString]-mods2Ln idx xs = intercalate ["-"] $ map (mod2Ln idx) xs--mod2Ln :: Set.Set Value -> Modify -> [BC.ByteString]-mod2Ln idx mod = [ attrVal2Ln idx (modName,attrName) ] ++ valLst- where- attrName = Value $ aName $ modAttr mod- valLst = map (\v -> attrVal2Ln idx (modAttr mod,v)) $ modAttrVals mod- modName = case mod of - (ModAdd _ _) -> Attribute "add"- (ModDelete _ _) -> Attribute "delete"- (ModReplace _ _) -> Attribute "replace"--dns :: LDIF -> Set.Set Value-dns (LDIF _ xs) = Set.fromList $ nub $ map (dn2last . reDN) xs--dn2last (DN xs) = snd $ head xs--main = do- args <- getArgs- case args of - [] -> putStrLn "Usage: ldif2html <input.ldif> [<input2.ldif> <input3.ldif> ... <inputN.ldif> <output.ldif>]"- [inp] -> do- doLDIF2HTML [inp] (BC.putStrLn)- putStrLn "# Done."- xs -> do- doLDIF2HTML (init xs) (BC.writeFile (last xs)) - putStrLn $ "## Processed : " ++ (unlines $ init xs)- putStrLn $ "## Written : " ++ (last xs)- where- doLDIF2HTML names outF = do- mls <- mapM (parseLDIFFile defaulLDIFConf) names- case lefts mls of - [] -> do- let idx = Set.unions $ map dns $ rights mls- outF $ BC.concat [ "<html><body bgcolor=lightyellow><pre>"- , BC.concat $ map (ldif2html idx) (rights mls) - , "</pre></body></html>" ]- xs -> mapM_ print xs- -- | Serialize LDIF to HTML- ldif2html :: Set.Set Value -> LDIF -> BC.ByteString- ldif2html idx (LDIF v xs) = BC.unlines $ (ver2str v) ++ (map (record2html idx) xs)--
− src/ldifdiff.hs
@@ -1,34 +0,0 @@-{-# LANGUAGE DeriveDataTypeable #-}--- | 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 System.Console.CmdArgs-import qualified Data.ByteString.Char8 as BC--progDesc = "Create delta LDIF between Source LDIF and Target LDIF"--data LdifDiff = LdifDiff { srcFile :: FilePath- , dstFile :: FilePath } deriving (Show, Data, Typeable)--defaultCfg = LdifDiff { srcFile = def &= typFile &= name "s" &= help "Source LDIF File"- , dstFile = def &= typFile &= name "t" &= help "Target LDIF File" }--main = do- cfg <- cmdArgs defaultCfg- execute cfg--execute (LdifDiff [] _ ) = putStrLn "Error: -s source file is mandatory" -execute (LdifDiff _ [] ) = putStrLn "Error: -t target file is mandatory"-execute (LdifDiff src dst) = do- ml1 <- parseLDIFFile defaulLDIFConf src- ml2 <- parseLDIFFile defaulLDIFConf dst- case rights [ml1,ml2] of - [l1,l2] -> case diffLDIF l1 l2 of- Left err -> putStrLn err- Right delta -> BC.putStrLn $ ldif2str delta- _ -> print $ lefts [ml1,ml2]
− src/ldifmodify.hs
@@ -1,42 +0,0 @@-{-# LANGUAGE DeriveDataTypeable, OverloadedStrings #-}--- | Apply LDAP operations within LDIF on another LDIF.--- | Without schema related verification like syntax, cardinality etc.-import Data.List-import Data.Either-import Data.Maybe-import Control.Monad -import System.FilePath -import System.Environment-import Text.LDIF-import System.Console.CmdArgs-import qualified Data.ByteString.Char8 as BC--progDesc = "Apply LDAP operations from LDIF to LDIF (like ldapmodify)"--data LdifModify = LdifModify { baseFile :: FilePath- , modFiles :: [FilePath]- , outFile :: FilePath } deriving (Show, Data, Typeable)--defaultCfg = LdifModify { baseFile = def &= typFile &= name "f" &= help "Base LDIF File"- , modFiles = def &= args &= typ "LDIF Files for applying"- , outFile = def &= typFile &= name "o" &= help "Output LDIF File" }--main = do- cfg <- cmdArgs defaultCfg- execute cfg--execute (LdifModify [] _ _) = putStrLn "Error: -f base LDIF File is mandatory"-execute (LdifModify _ [] _) = putStrLn "Error: no LDIF Files for applying provided"-execute (LdifModify _ _ []) = putStrLn "Error: -o output LDIF File is mandatory"-execute cfg = do- baseLDIF <- safeParseLDIFFile (baseFile cfg)- modLDIFs <- mapM (safeParseLDIFFile) (modFiles cfg)- let outLDIF = foldr (flip applyLDIF) baseLDIF modLDIFs- if length (outFile cfg) == 0 then do- BC.putStrLn (ldif2str outLDIF)- else do- BC.writeFile (outFile cfg) (ldif2str outLDIF)- putStrLn $ (outFile cfg) ++ " written."--safeParseLDIFFile :: FilePath -> IO LDIF-safeParseLDIFFile name = liftM (either (\e -> error $ "Can not parse: "++(show e)) (id)) (parseLDIFFile defaulLDIFConf name)
− src/ldifparse.hs
@@ -1,17 +0,0 @@--- | 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.ByteString.Char8 as BC--main = do- args <- getArgs- let name = args !! 0- ml1 <- parseLDIFFile defaulLDIFConf name- case ml1 of - Right l1 -> BC.putStrLn $ ldif2str l1- Left err -> print err
− src/ldifundo.hs
@@ -1,36 +0,0 @@-{-# LANGUAGE DeriveDataTypeable, OverloadedStrings #-}-import Data.List-import Data.Either-import Data.Maybe-import Control.Monad-import System.FilePath-import System.Environment-import Text.LDIF-import System.Console.CmdArgs-import qualified Data.ByteString.Char8 as BC--progDesc = "Calculate undo LDIF (rollback LDIF)"--data LdifUndo = LdifUndo { inFile :: FilePath- , outFile :: FilePath } deriving (Show, Data, Typeable)--defaultCfg = LdifUndo { inFile = def &= typFile &= name "f" &= help "Input LDIF File"- , outFile = def &= typFile &= name "o" &= help "Output LDIF File" }--main = do- cfg <- cmdArgs defaultCfg- execute cfg--execute (LdifUndo [] _) = putStrLn "Error: -f base LDIF File is mandatory"-execute cfg = do- inLDIF <- safeParseLDIFFile (inFile cfg)- let (outLDIF, wrn) = undoLDIF inLDIF- when (not $ null wrn) (putStrLn $ "Finished with warnings: " ++ (unlines $ map unlines wrn))- if length (outFile cfg) == 0 then do- BC.putStrLn (ldif2str outLDIF)- else do- BC.writeFile (outFile cfg) (ldif2str outLDIF)- putStrLn $ (outFile cfg) ++ " written."--safeParseLDIFFile :: FilePath -> IO LDIF-safeParseLDIFFile name = liftM (either (\e -> error $ "Can not parse: "++(show e)) (id)) (parseLDIFFile defaulLDIFConf name)