module Text.LDIF.Diff (
diffLDIF,
diffRecord,
compareLDIF
)
where
import Text.LDIF.Types
import Text.LDIF.Utils
import Data.Maybe
import Data.List (foldl', sortBy)
diffLDIF :: LDIF -> LDIF -> Either String LDIF
diffLDIF l1 l2 | getLDIFType l1 == LDIFContentType && getLDIFType l2 == LDIFContentType = Right (diffLDIF' l1 l2)
| otherwise = Left ("Diff supported only on Content LDIFs but SRC="
++(show $ getLDIFType l1)++" and DST="
++(show $ getLDIFType l2))
diffLDIF' :: LDIF -> LDIF -> LDIF
diffLDIF' l1@(LDIF _ c1) l2@(LDIF v2 c2) = LDIF v2 (changes ++ deletes ++ adds)
where
adds = map content2add $ filter (not . isEntryIn) c2
where
llc = createLookupTable l1
isEntryIn ex = case findRecordByDN llc (reDN ex) of
Nothing -> False
Just (ContentRecord _ _) -> True
Just (ChangeRecord _ _) -> error "Unexpected record type"
content2add (ContentRecord dn vals) = ChangeRecord dn (ChangeAdd vals)
content2add (ChangeRecord _ _) = error "Unexpected record type"
(changes,deletes) = (reverse $ fnu changes', fnu deletes')
where
fnu = filter (not . isDummyRecord)
l2c = createLookupTable l2
(changes',deletes') = foldl' processEntry ([],[]) c1
processEntry (cx,dx) e1 = procEntry' $ findRecordByDN l2c (reDN e1)
where
procEntry' Nothing = (cx, (ChangeRecord (reDN e1) ChangeDelete):dx)
procEntry' (Just e2) = ((fromJust $ diffRecord e1 e2):cx, dx)
diffRecord :: LDIFRecord -> LDIFRecord -> Maybe LDIFRecord
diffRecord r1 r2 | (reDN r1) /= (reDN r2) = Nothing
| otherwise = Just (ChangeRecord (reDN r1) (ChangeModify mods))
where
mods = delMods ++ addMods
addMods = map (\x -> ModAdd (fst x) [(snd x)]) addVals
delMods = map (\x -> ModDelete (fst x) [(snd x)]) delVals
addVals = filter (\x -> not $ elem x (coAttrVals r1)) (coAttrVals r2) :: [AttrValue]
delVals = filter (\x -> not $ elem x (coAttrVals r2)) (coAttrVals r1) :: [AttrValue]
compareLDIF :: LDIF -> LDIF -> ([LDIFRecord], [LDIFRecord])
compareLDIF l1@(LDIF _ c1) l2@(LDIF _ c2) = (sortBy cmpByDN r1, sortBy cmpByDN $ r2 ++ adds)
where
cmpByDN a b = (reDN a) `compare` (reDN b)
adds = filter (not . isEntryIn) c2
where
llc = createLookupTable l1
isEntryIn ex = case findRecordByDN llc (reDN ex) of
Nothing -> False
(Just _) -> True
(r1,r2) = foldl' processEntry ([],[]) c1
where
l2c = createLookupTable l2
processEntry (a1,a2) e1 = case findRecordByDN l2c (reDN e1) of
Nothing -> (e1:a1,a2)
Just e2 -> if e1 == e2 then (a1,a2) else (e1:a1,e2:a2)