{-# LANGUAGE CPP #-}

-- | A library for pkgtreediff for comparing trees of rpm packages
module Distribution.RPM.PackageTreeDiff
  (NVRA(..),
   readNVRA,
   RPMPkgDiff(..),
   diffPkgs,
   Ignore(..)
  ) where

#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>))
#endif
import Data.RPM.VerRel
import Data.RPM.NVRA
import Data.RPM.VerCmp (rpmVerCompare)

-- | Ignore describes how comparison is done
data Ignore = IgnoreNone    -- ^ do not ignore version or release
            | IgnoreRelease -- ^ ignore differences in release
            | IgnoreVersion -- ^ ignore differences in version
  deriving Ignore -> Ignore -> Bool
(Ignore -> Ignore -> Bool)
-> (Ignore -> Ignore -> Bool) -> Eq Ignore
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Ignore -> Ignore -> Bool
$c/= :: Ignore -> Ignore -> Bool
== :: Ignore -> Ignore -> Bool
$c== :: Ignore -> Ignore -> Bool
Eq

-- | RPMPkgDiff type encodes how a particular rpm package differs between trees
data RPMPkgDiff = PkgUpdate NVRA NVRA
                | PkgDowngrade NVRA NVRA
                | PkgAdd NVRA
                | PkgDel NVRA
                | PkgArch NVRA NVRA
  deriving RPMPkgDiff -> RPMPkgDiff -> Bool
(RPMPkgDiff -> RPMPkgDiff -> Bool)
-> (RPMPkgDiff -> RPMPkgDiff -> Bool) -> Eq RPMPkgDiff
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RPMPkgDiff -> RPMPkgDiff -> Bool
$c/= :: RPMPkgDiff -> RPMPkgDiff -> Bool
== :: RPMPkgDiff -> RPMPkgDiff -> Bool
$c== :: RPMPkgDiff -> RPMPkgDiff -> Bool
Eq

-- | Compare two lists of packages NVRAs
diffPkgs :: Ignore -> [NVRA] -> [NVRA] -> [RPMPkgDiff]
diffPkgs :: Ignore -> [NVRA] -> [NVRA] -> [RPMPkgDiff]
diffPkgs Ignore
_ [] [] = []
diffPkgs Ignore
ignore (NVRA
p:[NVRA]
ps) [] = NVRA -> RPMPkgDiff
PkgDel NVRA
p RPMPkgDiff -> [RPMPkgDiff] -> [RPMPkgDiff]
forall a. a -> [a] -> [a]
: Ignore -> [NVRA] -> [NVRA] -> [RPMPkgDiff]
diffPkgs Ignore
ignore [NVRA]
ps []
diffPkgs Ignore
ignore [] (NVRA
p:[NVRA]
ps) = NVRA -> RPMPkgDiff
PkgAdd NVRA
p RPMPkgDiff -> [RPMPkgDiff] -> [RPMPkgDiff]
forall a. a -> [a] -> [a]
: Ignore -> [NVRA] -> [NVRA] -> [RPMPkgDiff]
diffPkgs Ignore
ignore [] [NVRA]
ps
diffPkgs Ignore
ignore (NVRA
p1:[NVRA]
ps1) (NVRA
p2:[NVRA]
ps2) =
  case String -> String -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (NVRA -> String
rpmName NVRA
p1) (NVRA -> String
rpmName NVRA
p2) of
    Ordering
LT -> NVRA -> RPMPkgDiff
PkgDel NVRA
p1 RPMPkgDiff -> [RPMPkgDiff] -> [RPMPkgDiff]
forall a. a -> [a] -> [a]
: Ignore -> [NVRA] -> [NVRA] -> [RPMPkgDiff]
diffPkgs Ignore
ignore [NVRA]
ps1 (NVRA
p2NVRA -> [NVRA] -> [NVRA]
forall a. a -> [a] -> [a]
:[NVRA]
ps2)
    Ordering
EQ -> case Maybe RPMPkgDiff
diffPkg of
            Just RPMPkgDiff
diff -> (RPMPkgDiff
diff RPMPkgDiff -> [RPMPkgDiff] -> [RPMPkgDiff]
forall a. a -> [a] -> [a]
:)
            Maybe RPMPkgDiff
Nothing -> [RPMPkgDiff] -> [RPMPkgDiff]
forall a. a -> a
id
          ([RPMPkgDiff] -> [RPMPkgDiff]) -> [RPMPkgDiff] -> [RPMPkgDiff]
forall a b. (a -> b) -> a -> b
$ Ignore -> [NVRA] -> [NVRA] -> [RPMPkgDiff]
diffPkgs Ignore
ignore [NVRA]
ps1 [NVRA]
ps2
    Ordering
GT -> NVRA -> RPMPkgDiff
PkgAdd NVRA
p2 RPMPkgDiff -> [RPMPkgDiff] -> [RPMPkgDiff]
forall a. a -> [a] -> [a]
: Ignore -> [NVRA] -> [NVRA] -> [RPMPkgDiff]
diffPkgs Ignore
ignore (NVRA
p1NVRA -> [NVRA] -> [NVRA]
forall a. a -> [a] -> [a]
:[NVRA]
ps1) [NVRA]
ps2
  where
    diffPkg :: Maybe RPMPkgDiff
    diffPkg :: Maybe RPMPkgDiff
diffPkg =
      if NVRA -> String
rpmArch NVRA
p1 String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== NVRA -> String
rpmArch NVRA
p2
      then case Ignore -> VerRel -> VerRel -> Ordering
cmpVR Ignore
ignore (NVRA -> VerRel
rpmVerRel NVRA
p1) (NVRA -> VerRel
rpmVerRel NVRA
p2) of
             Ordering
LT -> RPMPkgDiff -> Maybe RPMPkgDiff
forall a. a -> Maybe a
Just (RPMPkgDiff -> Maybe RPMPkgDiff) -> RPMPkgDiff -> Maybe RPMPkgDiff
forall a b. (a -> b) -> a -> b
$ NVRA -> NVRA -> RPMPkgDiff
PkgUpdate NVRA
p1 NVRA
p2
             Ordering
EQ -> Maybe RPMPkgDiff
forall a. Maybe a
Nothing
             Ordering
GT -> RPMPkgDiff -> Maybe RPMPkgDiff
forall a. a -> Maybe a
Just (RPMPkgDiff -> Maybe RPMPkgDiff) -> RPMPkgDiff -> Maybe RPMPkgDiff
forall a b. (a -> b) -> a -> b
$ NVRA -> NVRA -> RPMPkgDiff
PkgDowngrade NVRA
p1 NVRA
p2
      else RPMPkgDiff -> Maybe RPMPkgDiff
forall a. a -> Maybe a
Just (RPMPkgDiff -> Maybe RPMPkgDiff) -> RPMPkgDiff -> Maybe RPMPkgDiff
forall a b. (a -> b) -> a -> b
$ NVRA -> NVRA -> RPMPkgDiff
PkgArch NVRA
p1 NVRA
p2

-- cmpVR True ignore release
cmpVR :: Ignore -> VerRel -> VerRel -> Ordering
cmpVR :: Ignore -> VerRel -> VerRel -> Ordering
cmpVR Ignore
IgnoreNone VerRel
vr VerRel
vr' = VerRel -> VerRel -> Ordering
forall a. Ord a => a -> a -> Ordering
compare VerRel
vr VerRel
vr'
cmpVR Ignore
IgnoreRelease (VerRel String
v String
_) (VerRel String
v' String
_) = String -> String -> Ordering
rpmVerCompare String
v String
v'
cmpVR Ignore
IgnoreVersion VerRel
_ VerRel
_ = Ordering
EQ