versions 3.3.2 → 3.4.0
raw patch · 5 files changed
+95/−110 lines, 5 filesdep +base-preludedep ~tasty-quickcheck
Dependencies added: base-prelude
Dependency ranges changed: tasty-quickcheck
Files
- CHANGELOG.md +5/−0
- Data/Versions.hs +14/−42
- README.md +1/−2
- test/Test.hs +65/−54
- versions.cabal +10/−12
CHANGELOG.md view
@@ -1,6 +1,11 @@ Changelog ========= +3.4.0+------+- Removed `ParseV` and surrounding machinery.+ Use `versioning` now instead of the `parseV` function.+ 3.3.2 ------ - GHC 8.4.1 compatibility.
Data/Versions.hs view
@@ -29,7 +29,7 @@ -- incrementing and has the best constraints on comparisons. -- -- == Using the Parsers--- In general, `parseV` is the function you want. It attempts to parse+-- In general, `versioning` is the function you want. It attempts to parse -- a given @Text@ using the three individual parsers, `semver`, `version` -- and `mess`. If one fails, it tries the next. If you know you only want -- to parse one specific version type, use that parser directly@@ -45,14 +45,12 @@ , VUnit(..), digits, str , VChunk , VSep(..)- -- * Parsers- , VParser(..), ParsingError- , semver, version, mess- -- ** Wrapped Parsers- , parseV, semverP, versionP, messP+ -- * Parsing Versions+ , ParsingError+ , versioning, semver, version, mess -- ** Megaparsec Parsers -- | For when you'd like to mix version parsing into some larger parser.- , semver', version', mess'+ , versioning', semver', version', mess' -- * Pretty Printing , prettyV, prettySemVer, prettyVer, prettyMess, parseErrorPretty -- * Lenses@@ -163,7 +161,7 @@ -- "1.2.4" -- @ _Versioning :: Traversal' T.Text Versioning-_Versioning f t = either (const (pure t)) (fmap prettyV . f) $ parseV t+_Versioning f t = either (const (pure t)) (fmap prettyV . f) $ versioning t {-# INLINE _Versioning #-} -- | Traverse some Text for its inner SemVer.@@ -536,38 +534,20 @@ -- | A synonym for the more verbose `megaparsec` error type. type ParsingError = ParseError (Token T.Text) Void --- | A wrapper for a parser function. Can be composed via their--- Monoid instance, such that a different parser can be tried--- if a previous one fails.-newtype VParser = VParser { runVP :: T.Text -> Either ParsingError Versioning }--instance Semigroup VParser where- -- | Will attempt the right parser if the left one fails.- (VParser f) <> (VParser g) = VParser h- where h t = either (const (g t)) Right $ f t--instance Monoid VParser where- -- | A parser which will always fail.- mempty = VParser $ \_ -> Ideal <$> semver ""--#if __GLASGOW_HASKELL__ < 841- mappend = (<>)-#endif- -- | Parse a piece of `T.Text` into either an (Ideal) `SemVer`, a (General) -- `Version`, or a (Complex) `Mess`.-parseV :: T.Text -> Either ParsingError Versioning-parseV = runVP $ semverP <> versionP <> messP+versioning :: T.Text -> Either ParsingError Versioning+versioning = parse versioning' "versioning" --- | A wrapped `SemVer` parser. Can be composed with other parsers.-semverP :: VParser-semverP = VParser $ fmap Ideal . semver+-- | Parse a `Versioning`. Assumes that the version number is the last token in the string.+versioning' :: Parsec Void T.Text Versioning+versioning' = try (fmap Ideal semver' <* eof) <|> try (fmap General version' <* eof) <|> (fmap Complex mess' <* eof) -- | Parse a (Ideal) Semantic Version. semver :: T.Text -> Either ParsingError SemVer semver = parse (semver' <* eof) "Semantic Version" --- | Internal megaparsec parser of 'semverP'.+-- | Internal megaparsec parser of `semver`. semver' :: Parsec Void T.Text SemVer semver' = SemVer <$> majorP <*> minorP <*> patchP <*> preRel <*> metaData @@ -610,30 +590,22 @@ sunit :: Parsec Void T.Text VUnit sunit = Str . T.pack <$> some letterChar --- | A wrapped `Version` parser. Can be composed with other parsers.-versionP :: VParser-versionP = VParser $ fmap General . version- -- | Parse a (General) `Version`, as defined above. version :: T.Text -> Either ParsingError Version version = parse (version' <* eof) "Version" --- | Internal megaparsec parser of 'versionP'.+-- | Internal megaparsec parser of `version`. version' :: Parsec Void T.Text Version version' = Version <$> optional (try epochP) <*> chunks <*> preRel epochP :: Parsec Void T.Text Word epochP = read <$> (some digitChar <* char ':') --- | A wrapped `Mess` parser. Can be composed with other parsers.-messP :: VParser-messP = VParser $ fmap Complex . mess- -- | Parse a (Complex) `Mess`, as defined above. mess :: T.Text -> Either ParsingError Mess mess = parse (mess' <* eof) "Mess" --- | Internal megaparsec parser of 'messP'.+-- | Internal megaparsec parser of `mess`. mess' :: Parsec Void T.Text Mess mess' = try node <|> leaf
README.md view
@@ -1,7 +1,6 @@ versions ======== -[](https://travis-ci.org/fosskers/versions) [](https://hackage.haskell.org/package/versions) [](http://stackage.org/nightly/package/versions) [](http://stackage.org/lts/package/versions)@@ -28,7 +27,7 @@ Usage ------In general, `parseV` is the function you want. It attempts to parse a given+In general, `versioning` is the function you want. It attempts to parse a given Text using the three individual parsers, `semver`, `version` and `mess`. If one fails, it tries the next. If you know you only want to parse one specific version type, use that parser directly (e.g. `semver`).
test/Test.hs view
@@ -1,21 +1,19 @@-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedStrings, NoImplicitPrelude #-} module Main where -import Data.Char-import Data.Either (isRight, isLeft)-import Data.Foldable (fold)-import Data.List (groupBy)-import Data.Monoid ((<>))-import Data.Text (Text, unpack, pack)-import Data.Versions-import Lens.Micro-import Test.QuickCheck-import Test.QuickCheck.Checkers-import Test.QuickCheck.Classes-import Test.Tasty-import Test.Tasty.HUnit-import Test.Tasty.QuickCheck+import BasePrelude hiding (Version, try)+import qualified Data.Text as T+import Data.Versions+import Lens.Micro+import Test.QuickCheck+import Test.QuickCheck.Checkers+import Test.QuickCheck.Classes+import Test.Tasty+import Test.Tasty.HUnit+import Test.Tasty.QuickCheck+import Text.Megaparsec+import Text.Megaparsec.Char --- @@ -37,7 +35,7 @@ instance Arbitrary VUnit where arbitrary = frequency [ (1, Digits . (+ 1) <$> arbitrary) , (1, s) ]- where s = Str . pack . map unletter <$> resize 10 (listOf1 arbitrary)+ where s = Str . T.pack . map unletter <$> resize 10 (listOf1 arbitrary) instance EqProp VUnit where a =-= b = eq a b@@ -55,31 +53,31 @@ a =-= b = eq a b -- | These don't need to parse as a SemVer.-goodVers :: [Text]+goodVers :: [T.Text] goodVers = [ "1", "1.2", "1.0rc0", "1.0rc1", "1.1rc1", "1.58.0-3", "44.0.2403.157-1" , "0.25-2", "8.u51-1", "21-2", "7.1p1-1", "20150826-1", "1:0.10.16-3" ] -messes :: [Text]+messes :: [T.Text] messes = [ "10.2+0.93+1-1", "003.03-3", "002.000-7", "20.26.1_0-2" ] -messComps :: [Text]+messComps :: [T.Text] messComps = [ "10.2+0.93+1-1", "10.2+0.93+1-2", "10.2+0.93+2-1" , "10.2+0.94+1-1", "10.3+0.93+1-1", "11.2+0.93+1-1", "12" ] -badSemVs :: [Text]+badSemVs :: [T.Text] badSemVs = [ "1", "1.2", "1.2.3+a1b2bc3.1-alpha.2", "a.b.c", "1.01.1" , "1.2.3+a1b!2c3.1" ] -goodSemVs :: [Text]+goodSemVs :: [T.Text] goodSemVs = [ "0.1.0", "1.2.3", "1.2.3-1", "1.2.3-alpha", "1.2.3-alpha.2" , "1.2.3+a1b2c3.1", "1.2.3-alpha.2+a1b2c3.1" ] -- | The exact example from `http://semver.org`-semverOrd :: [Text]+semverOrd :: [T.Text] semverOrd = [ "1.0.0-alpha", "1.0.0-alpha.1", "1.0.0-alpha.beta" , "1.0.0-beta", "1.0.0-beta.2", "1.0.0-beta.11", "1.0.0-rc.1" , "1.0.0"@@ -90,10 +88,10 @@ -- make this necessary, meaning `cabal` can't be simplified to ignore it. -- Logically, these are the same package, but for those 5 packages, they -- aren't.-cabalOrd :: [Text]+cabalOrd :: [T.Text] cabalOrd = [ "0.2", "0.2.0", "0.2.0.0" ] -versionOrd :: [Text]+versionOrd :: [T.Text] versionOrd = [ "0.9.9.9", "1.0.0.0", "1.0.0.1", "2" ] suite :: TestTree@@ -111,55 +109,55 @@ , testGroup "Unit Tests" [ testGroup "(Ideal) Semantic Versioning" [ testGroup "Bad Versions (shouldn't parse)" $- map (\s -> testCase (unpack s) $ assertBool "A bad version parsed" $ isLeft $ semver s) badSemVs+ map (\s -> testCase (T.unpack s) $ assertBool "A bad version parsed" $ isLeft $ semver s) badSemVs , testGroup "Good Versions (should parse)" $- map (\s -> testCase (unpack s) $ isomorphSV s) goodSemVs+ map (\s -> testCase (T.unpack s) $ isomorphSV s) goodSemVs , testGroup "Comparisons" $ testCase "1.2.3-alpha.2 == 1.2.3-alpha.2+a1b2c3.1" (assertBool "Equality test of two complicated SemVers failed" $ semver "1.2.3-alpha.2" == semver "1.2.3-alpha.2+a1b2c3.1") :- map (\(a,b) -> testCase (unpack $ a <> " < " <> b) $ comp semver a b)+ map (\(a,b) -> testCase (T.unpack $ a <> " < " <> b) $ comp semver a b) (zip semverOrd $ tail semverOrd) ] , testGroup "(General) Versions" [ testGroup "Good Versions" $- map (\s -> testCase (unpack s) $ isomorphV s) goodVers+ map (\s -> testCase (T.unpack s) $ isomorphV s) goodVers , testGroup "Comparisons" $ testCase "1.2-5 < 1.2.3-1" (comp version "1.2-5" "1.2.3-1") : testCase "1.0rc1 < 1.0" (comp version "1.0rc1" "1.0") : testCase "1.0 < 1:1.0" (comp version "1.0" "1:1.0") : testCase "1.1 < 1:1.0" (comp version "1.1" "1:1.0") : testCase "1.1 < 1:1.1" (comp version "1.1" "1:1.1") :- map (\(a,b) -> testCase (unpack $ a <> " < " <> b) $ comp version a b)+ map (\(a,b) -> testCase (T.unpack $ a <> " < " <> b) $ comp version a b) (zip cabalOrd (tail cabalOrd) <> zip versionOrd (tail versionOrd)) ] , testGroup "(Complex) Mess" [ testGroup "Good Versions" $- map (\s -> testCase (unpack s) $ isomorphM s) messes+ map (\s -> testCase (T.unpack s) $ isomorphM s) messes , testGroup "Comparisons" $- map (\(a,b) -> testCase (unpack $ a <> " < " <> b) $ comp mess a b) $+ map (\(a,b) -> testCase (T.unpack $ a <> " < " <> b) $ comp mess a b) $ zip messComps (tail messComps) ] , testGroup "Mixed Versioning" [ testGroup "Identification"- [ testCase "1.2.3 is SemVer" $ check $ isSemVer <$> parseV "1.2.3"- , testCase "1.2.3-1 is SemVer" $ check $ isSemVer <$> parseV "1.2.3-1"- , testCase "1.2.3-1+1 is SemVer" $ check $ isSemVer <$> parseV "1.2.3-1+1"- , testCase "1.2.3r1 is Version" $ check $ isVersion <$> parseV "1.2.3r1"- , testCase "0.25-2 is Version" $ check $ isVersion <$> parseV "0.25-2"- , testCase "1:1.2.3-1 is Version" $ check $ isVersion <$> parseV "1:1.2.3-1"- , testCase "1.2.3+1-1 is Mess" $ check $ isMess <$> parseV "1.2.3+1-1"- , testCase "000.007-1 is Mess" $ check $ isMess <$> parseV "000.007-1"- , testCase "20.26.1_0-2 is Mess" $ check $ isMess <$> parseV "20.26.1_0-2"+ [ testCase "1.2.3 is SemVer" $ check $ isSemVer <$> versioning "1.2.3"+ , testCase "1.2.3-1 is SemVer" $ check $ isSemVer <$> versioning "1.2.3-1"+ , testCase "1.2.3-1+1 is SemVer" $ check $ isSemVer <$> versioning "1.2.3-1+1"+ , testCase "1.2.3r1 is Version" $ check $ isVersion <$> versioning "1.2.3r1"+ , testCase "0.25-2 is Version" $ check $ isVersion <$> versioning "0.25-2"+ , testCase "1:1.2.3-1 is Version" $ check $ isVersion <$> versioning "1:1.2.3-1"+ , testCase "1.2.3+1-1 is Mess" $ check $ isMess <$> versioning "1.2.3+1-1"+ , testCase "000.007-1 is Mess" $ check $ isMess <$> versioning "000.007-1"+ , testCase "20.26.1_0-2 is Mess" $ check $ isMess <$> versioning "20.26.1_0-2" ] , testGroup "Isomorphisms" $- map (\s -> testCase (unpack s) $ isomorph s) $ goodSemVs ++ goodVers ++ messes+ map (\s -> testCase (T.unpack s) $ isomorph s) $ goodSemVs ++ goodVers ++ messes , testGroup "Comparisons"- [ testCase "1.2.2r1-1 < 1.2.3-1" $ comp parseV "1.2.2r1-1" "1.2.3-1"- , testCase "1.2.3-1 < 1.2.4r1-1" $ comp parseV "1.2.3-1" "1.2.4r1-1"- , testCase "1.2.3-1 < 2+0007-1" $ comp parseV "1.2.3-1" "2+0007-1"- , testCase "1.2.3r1-1 < 2+0007-1" $ comp parseV "1.2.3r1-1" "2+0007-1"- , testCase "1.2-5 < 1.2.3-1" $ comp parseV "1.2-5" "1.2.3-1"+ [ testCase "1.2.2r1-1 < 1.2.3-1" $ comp versioning "1.2.2r1-1" "1.2.3-1"+ , testCase "1.2.3-1 < 1.2.4r1-1" $ comp versioning "1.2.3-1" "1.2.4r1-1"+ , testCase "1.2.3-1 < 2+0007-1" $ comp versioning "1.2.3-1" "2+0007-1"+ , testCase "1.2.3r1-1 < 2+0007-1" $ comp versioning "1.2.3r1-1" "2+0007-1"+ , testCase "1.2-5 < 1.2.3-1" $ comp versioning "1.2-5" "1.2.3-1" ] ] , testGroup "Lenses and Traversals"@@ -168,25 +166,29 @@ , testCase "SemVer - Get patches" patches , testCase "Traverse `General` as `Ideal`" noInc ]+ , testGroup "Megaparsec Behaviour"+ [ testCase "manyTill" $ parse nameGrab "manyTill" "linux-firmware-3.2.14-1-x86_64.pkg.tar.xz" @?= Right "linux-firmware"+ , testCase "Extracting version" $ parse versionGrab "extraction" "linux-firmware-3.2.14-1-x86_64.pkg.tar.xz" @?= Right(Ideal $ SemVer 3 2 14 [[Digits 1]] [])+ ] ] ] -- | Does pretty-printing return a Versioning to its original form?-isomorph :: Text -> Assertion-isomorph t = Right t @=? (prettyV <$> parseV t)+isomorph :: T.Text -> Assertion+isomorph t = Right t @=? (prettyV <$> versioning t) -- | Does pretty-printing return a Version to its original form?-isomorphV :: Text -> Assertion+isomorphV :: T.Text -> Assertion isomorphV t = Right t @=? (prettyVer <$> version t) -- | Does pretty-printing return a SemVer to its original form?-isomorphSV :: Text -> Assertion+isomorphSV :: T.Text -> Assertion isomorphSV t = Right t @=? (prettySemVer <$> semver t) -isomorphM :: Text -> Assertion+isomorphM :: T.Text -> Assertion isomorphM t = Right t @=? (prettyMess <$> mess t) -comp :: Ord b => (Text -> Either a b) -> Text -> Text -> Assertion+comp :: Ord b => (T.Text -> Either a b) -> T.Text -> T.Text -> Assertion comp f a b = check $ (<) <$> f a <*> f b check :: Either a Bool -> Assertion@@ -215,11 +217,20 @@ where v = General $ Version Nothing [] [] incFromT :: Assertion-incFromT = (("1.2.3" :: Text) & patch %~ (+ 1)) @?= "1.2.4"+incFromT = (("1.2.3" :: T.Text) & patch %~ (+ 1)) @?= "1.2.4" patches :: Assertion patches = ps @?= [3,4,5]- where ps = (["1.2.3","2.3.4","3.4.5"] :: [Text]) ^.. each . patch+ where ps = (["1.2.3","2.3.4","3.4.5"] :: [T.Text]) ^.. each . patch main :: IO () main = defaultMain suite++nameGrab :: Parsec Void T.Text T.Text+nameGrab = T.pack <$> manyTill anyChar (try finished)+ where finished = char '-' *> lookAhead digitChar++versionGrab :: Parsec Void T.Text Versioning+versionGrab = manyTill anyChar (try finished) *> ver+ where finished = char '-' *> lookAhead digitChar+ ver = fmap Ideal semver' <|> fmap General version' <|> fmap Complex mess'
versions.cabal view
@@ -1,11 +1,11 @@--- This file has been generated from package.yaml by hpack version 0.20.0.+-- This file has been generated from package.yaml by hpack version 0.28.2. -- -- see: https://github.com/sol/hpack ----- hash: ade99e86a1b2ba008cc0e453113e07938d16e488a28e2f5fcdfb8b61e33d7a6c+-- hash: afb8248e886b4197b3f7e3c3eb5132afb1409a8ac97bcf914795a9a3fd2ffdd7 name: versions-version: 3.3.2+version: 3.4.0 synopsis: Types and parsers for software version numbers. description: A library for parsing and comparing software version numbers. We like to give version numbers to our software in a myriad of ways. Some ways follow strict guidelines for incrementing and comparison. Some follow conventional wisdom and are generally self-consistent. Some are just plain asinine. This library provides a means of parsing and comparing /any/ style of versioning, be it a nice Semantic Version like this: .@@ -17,23 +17,19 @@ . Please switch to <http://semver.org Semantic Versioning> if you aren't currently using it. It provides consistency in version incrementing and has the best constraints on comparisons. category: Data+homepage: https://gitlab.com/fosskers/versions author: Colin Woodbury-maintainer: colingw@gmail.com+maintainer: colin@fosskers.ca license: BSD3 license-file: LICENSE build-type: Simple cabal-version: >= 1.10- extra-source-files: CHANGELOG.md README.md -source-repository head- type: git- location: git://github.com/fosskers/haskell-versions.git- library- ghc-options: -fwarn-unused-imports -fwarn-unused-binds -fwarn-name-shadowing -fwarn-unused-matches -fwarn-incomplete-patterns -Wincomplete-uni-patterns+ ghc-options: -fwarn-unused-imports -fwarn-unused-binds -fwarn-name-shadowing -fwarn-unused-matches -fwarn-incomplete-patterns -fwarn-redundant-constraints -Wincomplete-uni-patterns build-depends: base >=4.8 && <4.12 , deepseq >=1.4 && <1.5@@ -49,15 +45,17 @@ main-is: Test.hs hs-source-dirs: test- ghc-options: -fwarn-unused-imports -fwarn-unused-binds -fwarn-name-shadowing -fwarn-unused-matches -fwarn-incomplete-patterns -Wincomplete-uni-patterns -threaded -with-rtsopts=-N+ ghc-options: -fwarn-unused-imports -fwarn-unused-binds -fwarn-name-shadowing -fwarn-unused-matches -fwarn-incomplete-patterns -fwarn-redundant-constraints -Wincomplete-uni-patterns -threaded -with-rtsopts=-N build-depends: QuickCheck >=2.9 && <2.12 , base >=4.8 && <4.12+ , base-prelude , checkers >=0.4 && <0.5+ , megaparsec >=6 && <7 , microlens >=0.4 && <0.5 , tasty >=0.10.1.2 , tasty-hunit >=0.9.2- , tasty-quickcheck >=0.8 && <0.10+ , tasty-quickcheck >=0.8 && <0.11 , text >=1.2 && <1.3 , versions default-language: Haskell2010