hackport-0.6.4: Portage/Version.hs
{-# LANGUAGE CPP #-}
{-|
Author : Andres Loeh <kosmikus@gentoo.org>
Stability : provisional
Portability : haskell98
Version parser, according to Portage spec.
Shamelessly borrowed from exi, ported from Parsec to ReadP
-}
module Portage.Version (
Version(..),
Suffix(..),
fromCabalVersion,
toCabalVersion,
is_live
) where
import qualified Distribution.Version as Cabal
import Distribution.Pretty (Pretty(..))
import Distribution.Parsec (Parsec(..))
import qualified Distribution.Compat.CharParsing as P
import qualified Text.PrettyPrint as Disp
import Text.PrettyPrint ((<>))
import qualified Data.Char as Char (isAlpha, isDigit)
#if MIN_VERSION_base(4,11,0)
import Prelude hiding ((<>))
#endif
data Version = Version { versionNumber :: [Int] -- [1,42,3] ~= 1.42.3
, versionChar :: (Maybe Char) -- optional letter
, versionSuffix :: [Suffix]
, versionRevision :: Int -- revision, 0 means none
}
deriving (Eq, Ord, Show, Read)
instance Pretty Version where
pretty (Version ver c suf rev) =
dispVer ver <> dispC c <> dispSuf suf <> dispRev rev
where
dispVer = Disp.hcat . Disp.punctuate (Disp.char '.') . map Disp.int
dispC = maybe Disp.empty Disp.char
dispSuf = Disp.hcat . map pretty
dispRev 0 = Disp.empty
dispRev n = Disp.text "-r" <> Disp.int n
instance Parsec Version where
parsec = do
ver <- P.sepBy1 digits (P.char '.')
c <- P.optional $ P.satisfy Char.isAlpha
suf <- P.many parsec
rev <- P.option 0 $ P.string "-r" *> digits
return $ Version ver c suf rev
-- foo-9999* is treated as live ebuild
-- Cabal-1.17.9999* as well
is_live :: Version -> Bool
is_live v =
case vs of
-- nonempty
(_:_) | many_nines (last vs) -> True
_ -> False
where vs = versionNumber v
many_nines n = is_big n && all_nines n
is_big n = n >= 9999
all_nines n = (all (== '9') . show) n
data Suffix = Alpha Int | Beta Int | Pre Int | RC Int | P Int
deriving (Eq, Ord, Show, Read)
instance Pretty Suffix where
pretty suf = case suf of
Alpha n -> Disp.text "_alpha" <> dispPos n
Beta n -> Disp.text "_beta" <> dispPos n
Pre n -> Disp.text "_pre" <> dispPos n
RC n -> Disp.text "_rc" <> dispPos n
P n -> Disp.text "_p" <> dispPos n
where
dispPos :: Int -> Disp.Doc
dispPos 0 = Disp.empty
dispPos n = Disp.int n
instance Parsec Suffix where
parsec = P.char '_'
>> P.choice
[ P.string "alpha" >> fmap Alpha maybeDigits
, P.string "beta" >> fmap Beta maybeDigits
, P.string "pre" >> fmap Pre maybeDigits
, P.string "rc" >> fmap RC maybeDigits
, P.string "p" >> fmap P maybeDigits
]
where
maybeDigits = P.option 0 digits
fromCabalVersion :: Cabal.Version -> Version
fromCabalVersion cabal_version = Version (Cabal.versionNumbers cabal_version) Nothing [] 0
toCabalVersion :: Version -> Maybe Cabal.Version
toCabalVersion (Version nums Nothing [] _) = Just (Cabal.mkVersion nums)
toCabalVersion _ = Nothing
digits :: P.CharParsing m => m Int
digits = read <$> P.munch1 Char.isDigit