{-# LANGUAGE CPP #-} {-| Author : Andres Loeh 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.Text (Text(..)) import qualified Distribution.Compat.ReadP as Parse 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) -- 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) 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 instance Text Version where disp (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 disp dispRev 0 = Disp.empty dispRev n = Disp.text "-r" <> Disp.int n parse = do ver <- Parse.sepBy1 digits (Parse.char '.') c <- Parse.option Nothing (fmap Just (Parse.satisfy Char.isAlpha)) suf <- Parse.many parse rev <- Parse.option 0 (Parse.string "-r" >> digits) return (Version ver c suf rev) instance Text Suffix where disp 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 parse = Parse.char '_' >> Parse.choice [ Parse.string "alpha" >> fmap Alpha maybeDigits , Parse.string "beta" >> fmap Beta maybeDigits , Parse.string "pre" >> fmap Pre maybeDigits , Parse.string "rc" >> fmap RC maybeDigits , Parse.string "p" >> fmap P maybeDigits ] where maybeDigits = Parse.option 0 digits digits :: Parse.ReadP r Int digits = fmap read (Parse.munch1 Char.isDigit)