module Debian.Debianize.VersionSplits
( DebBase(DebBase, unDebBase)
, VersionSplits(..)
, makePackage
, insertSplit
, cabalFromDebian
, cabalFromDebian'
, debianFromCabal
, packageRangesFromVersionSplits
, doSplits
) where
import Data.Generics (Data, Typeable)
import Data.Map as Map (elems, Map, mapMaybeWithKey)
import Data.Set as Set (fromList, Set, toList)
import Debian.Debianize.Interspersed (foldTriples, Interspersed(leftmost, pairs, foldInverted))
import Debian.Orphans ()
import qualified Debian.Relation as D (VersionReq(..))
import Debian.Version (DebianVersion, parseDebianVersion')
#if MIN_VERSION_Cabal(2,0,0)
import Distribution.Package (PackageIdentifier(..), PackageName)
import Distribution.Package (mkPackageName)
import Distribution.Version (showVersion, Version)
#else
import Data.Version (showVersion, Version(Version))
import Distribution.Package (PackageIdentifier(..), PackageName(..))
#endif
import Distribution.Version (anyVersion, earlierVersion, intersectVersionRanges, orLaterVersion, VersionRange)
import Prelude hiding (init, log, unlines)
newtype DebBase = DebBase {unDebBase :: String} deriving (Eq, Ord, Read, Show, Data, Typeable)
data VersionSplits
= VersionSplits {
oldestPackage :: DebBase
, splits :: [(Version, DebBase)]
} deriving (Eq, Ord, Data, Typeable)
instance Show VersionSplits where
show s = foldr (\ (v, b) r -> ("insertSplit (" ++ show v ++ ") (" ++ show b ++ ") (" ++ r ++ ")")) ("makePackage (" ++ show (oldestPackage s) ++ ")") (splits s)
instance Interspersed VersionSplits DebBase Version where
leftmost (VersionSplits {oldestPackage = p}) = p
pairs (VersionSplits {splits = xs}) = xs
makePackage :: DebBase -> VersionSplits
makePackage name = VersionSplits {oldestPackage = name, splits = []}
insertSplit :: Version
-> DebBase
-> VersionSplits
-> VersionSplits
#if MIN_VERSION_Cabal(2,0,0)
insertSplit ver ltname sp@(VersionSplits {}) =
#else
insertSplit ver@(Version _ _) ltname sp@(VersionSplits {}) =
#endif
case splits sp of
(ver', _) : _ | ver' > ver -> sp {oldestPackage = ltname, splits = (ver, oldestPackage sp) : splits sp}
(ver', name) : _ | ver' == ver && name == ltname -> sp
[] -> sp {oldestPackage = ltname, splits = [(ver, oldestPackage sp)]}
_ -> sp {splits = reverse (insert (reverse (splits sp)))}
where
insert ((ver', name') : more) =
if ver' < ver
then (ver, name') : (ver', ltname) : more
else (ver', name') : insert more
insert [] = [(ver, oldestPackage sp)]
packageRangesFromVersionSplits :: VersionSplits -> [(DebBase, VersionRange)]
packageRangesFromVersionSplits s =
foldInverted (\ older dname newer more ->
(dname, intersectVersionRanges (maybe anyVersion orLaterVersion older) (maybe anyVersion earlierVersion newer)) : more)
[]
s
debianFromCabal :: VersionSplits -> PackageIdentifier -> DebBase
debianFromCabal s p =
doSplits s (Just (D.EEQ debVer))
where debVer = parseDebianVersion' (showVersion (pkgVersion p))
cabalFromDebian' :: Map PackageName VersionSplits -> DebBase -> Version -> PackageIdentifier
cabalFromDebian' mp base ver =
PackageIdentifier (cabalFromDebian mp base dver) ver
where dver = parseDebianVersion' (showVersion ver)
cabalFromDebian :: Map PackageName VersionSplits -> DebBase -> DebianVersion -> PackageName
cabalFromDebian mp base@(DebBase name) ver =
case Set.toList pset of
[x] -> x
#if MIN_VERSION_Cabal(2,0,0)
[] -> mkPackageName name
#else
[] -> PackageName name
#endif
l -> error $ "Error, multiple cabal package names associated with " ++ show base ++ ": " ++ show l
where
pset :: Set PackageName
pset = Set.fromList $ Map.elems $
Map.mapMaybeWithKey
(\ p s -> if doSplits s (Just (D.EEQ ver)) == base then Just p else Nothing)
mp
doSplits :: VersionSplits -> Maybe D.VersionReq -> DebBase
doSplits s version =
foldTriples' (\ ltName v geName _ ->
let split = parseDebianVersion' (showVersion v) in
case version of
Nothing -> geName
Just (D.SLT v') | v' <= split -> ltName
Just (D.EEQ v') | v' < split -> ltName
Just (D.LTE v') | v' < split -> ltName
Just (D.GRE v') | v' < split -> ltName
Just (D.SGR v') | v' < split -> ltName
_ -> geName)
(oldestPackage s)
s
where
foldTriples' :: (DebBase -> Version -> DebBase -> DebBase -> DebBase) -> DebBase -> VersionSplits -> DebBase
foldTriples' = foldTriples