stackage-server/Stackage/Snapshot/Diff.hs
2015-10-17 20:29:14 +03:00

66 lines
2.6 KiB
Haskell

{-# LANGUAGE PartialTypeSignatures #-}
module Stackage.Snapshot.Diff
( getSnapshotDiff
, snapshotDiff
, SnapshotDiff()
, toDiffList
, VersionChange(..)
, WithSnapshotNames(..)
) where
import Data.Align
import Data.Aeson.Extra
import qualified Data.HashMap.Strict as HashMap
import Control.Arrow
import ClassyPrelude
import Data.These
import Stackage.Database (SnapshotId, PackageListingInfo(..),
GetStackageDatabase, getPackages)
import Stackage.Database.Types (SnapName)
import Types
import Web.PathPieces
data WithSnapshotNames a
= WithSnapshotNames SnapName SnapName a
newtype SnapshotDiff
= SnapshotDiff { unSnapshotDiff :: HashMap PackageName VersionChange }
deriving (Show, Eq, Generic, Typeable)
instance ToJSON (WithSnapshotNames SnapshotDiff) where
toJSON (WithSnapshotNames nameA nameB (SnapshotDiff diff)) =
object [ "comparing" .= [toPathPiece nameA, toPathPiece nameB]
, "diff" .= Object (toJSONMap (WithSnapshotNames nameA nameB <$> diff))
]
toDiffList :: SnapshotDiff -> [(PackageName, VersionChange)]
toDiffList = sortOn (toCaseFold . unPackageName . fst) . HashMap.toList . unSnapshotDiff
-- | Versions of a package as it occurs in the listings provided to `snapshotDiff`.
--
-- Would be represented with `These v1 v2` if the package is present in both listings,
-- otherwise it would be `This v1` if the package is present only in the first listing,
-- or `That v2` if only in the second.
newtype VersionChange = VersionChange { unVersionChange :: These Version Version }
deriving (Show, Eq, Generic, Typeable)
instance ToJSON (WithSnapshotNames VersionChange) where
toJSON (WithSnapshotNames (toJSONKey -> aKey) (toJSONKey -> bKey) change) =
case change of
VersionChange (This a) -> object [ aKey .= a ]
VersionChange (That b) -> object [ bKey .= b ]
VersionChange (These a b) -> object [ aKey .= a, bKey .= b ]
changed :: VersionChange -> Bool
changed = these (const True) (const True) (/=) . unVersionChange
getSnapshotDiff :: GetStackageDatabase m => SnapshotId -> SnapshotId -> m SnapshotDiff
getSnapshotDiff a b = snapshotDiff <$> getPackages a <*> getPackages b
snapshotDiff :: [PackageListingInfo] -> [PackageListingInfo] -> SnapshotDiff
snapshotDiff as bs =
SnapshotDiff $ HashMap.filter changed
$ alignWith VersionChange (toMap as) (toMap bs)
where
toMap = HashMap.fromList . map (PackageName . pliName &&& Version . pliVersion)