packages feed

pkgtreediff-0.5.0: src/Distribution/RPM/PackageTreeDiff.hs

{-# LANGUAGE CPP #-}

-- | A library for pkgtreediff for comparing trees of rpm packages
module Distribution.RPM.PackageTreeDiff
  (NVRA(..),
   readNVRA,
   RPMPkgDiff(..),
   diffPkgs,
   Ignore(..),
   Mode(..),
  ) 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)

-- | Mode describes the kind of summary generated by compareDirs
data Mode = AutoSummary
          | NoSummary
          | ShowSummary
          | Added
          | Deleted
          | Updated
          | Downgraded
          | RST
  deriving Eq

-- | 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 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 Eq

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

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