hark-0.2: src/Parsers/Version.hs
{-----------------------------------------------------------------
(c) 2008-2009 Markus Dittrich
This program is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public
License Version 3 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License Version 3 for more details.
You should have received a copy of the GNU General Public
License along with this program; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
--------------------------------------------------------------------}
-- | this parser module contains functions that allow to parse
-- and compare ebuild version numbers
module Parsers.Version ( split_version
, test_NumCharTok
, test_Revision
, remove_trailing_zeros
, VersionTok(NumTok,Suffix,Revision)
, SuffixChoice(Alpha,Beta,Pre,Rc,P)
) where
-- imports
import qualified Data.ByteString as B(ByteString, split, splitAt,
takeWhile)
import qualified Data.ByteString.Char8 as BC(pack)
import Prelude
import Text.Regex.PCRE((=~))
import Word(Word8)
-- local imports
import Helpers.ByteString(colonW, dashW, glob, globW, periodW,
underscoreW)
-- | keeps track of the type of version suffix
data SuffixChoice = Alpha | Beta | Pre | Rc | P
deriving(Enum,Eq,Ord,Show)
-- | keeps track of the token type in a version string
data VersionTok = NumTok B.ByteString | Suffix SuffixChoice
| Revision
deriving(Eq,Show)
-- | default instance of versionTok
instance Ord VersionTok where
(NumTok a) <= (NumTok b) = a <= b
Revision <= _ = True
(Suffix _) <= _ = True
_ <= Revision = False
_ <= (Suffix _) = False
-- | simple function to test if an VersionTok data element
-- is of type NumTok or CharTok
test_NumCharTok :: VersionTok -> Bool
test_NumCharTok x = case x of
NumTok _ -> True
_ -> False
-- | simple function to test if an VersionTok data element
-- is of type Revision
test_Revision :: VersionTok -> Bool
test_Revision x = case x of
Revision -> True
_ -> False
-- | parses the tokenized version information from a list
-- of ByteString into a list of VersionTok so we can
-- compare it more efficiently
parse_into_VersionTok :: [B.ByteString] -> [VersionTok]
parse_into_VersionTok list = parse [] (reverse list)
where
parse :: [VersionTok] -> [B.ByteString] -> [VersionTok]
parse acc [] = acc
parse acc (x:xs)
| x =~ "[:][0-9]+" = parse (NumTok preEAPI1:acc) xs
| x =~ "[*]$" = parse (NumTok preGlob:NumTok glob:acc) xs
| x =~ "alpha" = parse (Suffix Alpha:acc) xs
| x =~ "beta" = parse (Suffix Beta:acc) xs
| x =~ "pre" = parse (Suffix Pre:acc) xs
| x =~ "rc" = parse (Suffix Rc:acc) xs
| x =~ "p" = parse (Suffix P:acc) xs
| x =~ "r" = parse (Revision:acc) xs
| x =~ "^[a-z]$" = parse (NumTok x:acc) xs
| otherwise = parse (NumTok x:acc) xs
where
preGlob = B.takeWhile (\z -> z /= globW) x
preEAPI1 = B.takeWhile (\z -> z /= colonW) x
-- | split a version number into tokens
split_version :: B.ByteString -> [VersionTok]
split_version = parse_into_VersionTok . separate_number_suffix
. separate_final_char . initial_parse
-- | function separating a version string at instances
-- of ".", "-", and "_"
initial_parse :: B.ByteString -> [B.ByteString]
initial_parse string =
let
stage1 = parse_sep periodW string
stage2 = flatten $ map (parse_sep underscoreW) stage1
in
flatten $ map (parse_sep dashW) stage2
-- | function separating off the optional characted after
-- the intial numbers
separate_final_char :: [B.ByteString] -> [B.ByteString]
separate_final_char = flatten . map num_match
where
num_match :: B.ByteString -> [B.ByteString]
num_match string =
let
(a,b) = string =~ "([0-9]+)[a-z]$" :: (Int,Int)
(num,letter) = B.splitAt (b-1) string
in
if a == -1 then
[string]
else
[num,letter]
-- | function splitting the optional alpha, beta, pre, rc, p,
-- and r suffices and the optional integer following them
separate_number_suffix :: [B.ByteString] -> [B.ByteString]
separate_number_suffix = flatten . map suffix_match
where
suffix_match :: B.ByteString -> [B.ByteString]
suffix_match string =
let
(a,b) = string =~ "^(alpha|beta|pre|rc|p|r)" :: (Int,Int)
(name,num) = B.splitAt b string
in
if a == -1 then
[string]
else
[name,num]
-- | parse a version string with a certain separator
parse_sep :: Word8 -> B.ByteString -> [B.ByteString]
parse_sep sep string = B.split sep string
-- | flatten a list
flatten :: [[a]] -> [a]
flatten = foldl (++) []
-- | NumTok zero
zeroTok :: VersionTok
zeroTok = NumTok $ BC.pack "0"
-- | remove trailing zeros from a list of NumToks
remove_trailing_zeros :: [VersionTok] -> [VersionTok]
remove_trailing_zeros = reverse . dropWhile ( \x -> x == zeroTok )
. reverse