packages feed

staversion 0.1.1.0 → 0.1.2.0

raw patch · 14 files changed

+263/−55 lines, 14 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Staversion.Internal.BuildPlan: parseVersionText :: Text -> Maybe Version
+ Staversion.Internal.BuildPlan: instance GHC.Base.Monoid Staversion.Internal.BuildPlan.BuildPlan
+ Staversion.Internal.BuildPlan.Hackage: data RegisteredVersions
+ Staversion.Internal.BuildPlan.Hackage: fetchPreferredVersions :: Manager -> PackageName -> IO (Either ErrorMsg RegisteredVersions)
+ Staversion.Internal.BuildPlan.Hackage: instance Data.Aeson.Types.FromJSON.FromJSON Staversion.Internal.BuildPlan.Hackage.RegisteredVersions
+ Staversion.Internal.BuildPlan.Hackage: instance GHC.Classes.Eq Staversion.Internal.BuildPlan.Hackage.RegisteredVersions
+ Staversion.Internal.BuildPlan.Hackage: instance GHC.Classes.Ord Staversion.Internal.BuildPlan.Hackage.RegisteredVersions
+ Staversion.Internal.BuildPlan.Hackage: instance GHC.Show.Show Staversion.Internal.BuildPlan.Hackage.RegisteredVersions
+ Staversion.Internal.BuildPlan.Hackage: latestVersion :: RegisteredVersions -> Maybe Version
+ Staversion.Internal.BuildPlan.Hackage: parsePreferredVersionsJSON :: ByteString -> Either ErrorMsg RegisteredVersions
+ Staversion.Internal.BuildPlan.Version: VersionJSON :: Version -> VersionJSON
+ Staversion.Internal.BuildPlan.Version: [unVersionJSON] :: VersionJSON -> Version
+ Staversion.Internal.BuildPlan.Version: instance Data.Aeson.Types.FromJSON.FromJSON Staversion.Internal.BuildPlan.Version.VersionJSON
+ Staversion.Internal.BuildPlan.Version: instance GHC.Classes.Eq Staversion.Internal.BuildPlan.Version.VersionJSON
+ Staversion.Internal.BuildPlan.Version: instance GHC.Classes.Ord Staversion.Internal.BuildPlan.Version.VersionJSON
+ Staversion.Internal.BuildPlan.Version: instance GHC.Show.Show Staversion.Internal.BuildPlan.Version.VersionJSON
+ Staversion.Internal.BuildPlan.Version: newtype VersionJSON
+ Staversion.Internal.BuildPlan.Version: parseVersionText :: Text -> Maybe Version
+ Staversion.Internal.Query: SourceHackage :: PackageSource
- Staversion.Internal.BuildPlan: loadBuildPlan :: BuildPlanManager -> PackageSource -> IO (Either ErrorMsg BuildPlan)
+ Staversion.Internal.BuildPlan: loadBuildPlan :: BuildPlanManager -> [PackageName] -> PackageSource -> IO (Either ErrorMsg BuildPlan)

Files

ChangeLog.md view
@@ -1,5 +1,9 @@ # Revision history for staversion +## 0.1.2.0  -- 2016-11-10++* New option `--hackage`, which searches hackage for the latest version number.+ ## 0.1.1.0  -- 2016-11-03  * Now staversion fetches build plan YAML files over network, if necessary.
README.md view
@@ -2,7 +2,7 @@  ![travis status](https://api.travis-ci.org/debug-ito/staversion.png) -staversion is a command-line tool to look for version numbers for Haskell packages in specific stackage resolvers. It answers to questions like "What version is the package X in stackage lts-Y.ZZ?" It aims to make it easier to write `build-depends` section in YOUR_PACKAGE.cabal.+staversion is a command-line tool to look for version numbers of Haskell packages. It mainly focuses on package versions in stackage, i.e. it answers to questions like "What version is the package X in stackage lts-Y.ZZ?" It aims to make it easier to write `build-depends` section in YOUR_PACKAGE.cabal.      $ staversion --resolver lts-4.2 conduit     ------ lts-4.2@@ -15,21 +15,29 @@     ------ lts-7.0     conduit ==1.2.7     -    $ staversion --resolver lts-4.2 --resolver lts-7.0 conduit base+    $ staversion --resolver lts-4.2 --resolver lts-6 conduit base     ------ lts-4.2     conduit ==1.2.6.1,     base ==4.8.2.0     -    ------ lts-7.0-    conduit ==1.2.7,-    base ==4.9.0.0+    ------ lts-6+    conduit ==1.2.8,+    base ==4.8.2.0  staversion first reads build plan YAML files that are stored locally in your computer, then it tries to fetch them over network. +You can also look up the latest version numbers hosted on hackage. +    $ staversion --hackage conduit base+    ------ latest in hackage+    conduit ==1.2.8,+    base ==4.9.0.0++See `--help` message for detail.++ ## TODO -- Search for the latest version numbers hosted in hackage. - Read `build-depends` sections .cabal files for package name queries. - Show version number ranges supported by the given resolvers. - Cache build plans in some local storage (SQLite?)
src/Staversion/Internal/BuildPlan.hs view
@@ -4,6 +4,7 @@ -- Maintainer: Toshio Ito <debug.ito@gmail.com> -- -- __This is an internal module. End-users should not use it.__+{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Staversion.Internal.BuildPlan        ( -- * Entry APIs          BuildPlan,@@ -13,7 +14,6 @@          loadBuildPlan,          -- * Low-level APIs          loadBuildPlanYAML,-         parseVersionText,          -- * For tests          _setDisambiguator        ) where@@ -22,22 +22,21 @@ import Control.Exception (throwIO, catchJust, IOException, catch) import Control.Monad.Trans.Except (runExceptT, ExceptT(..)) import Control.Monad.IO.Class (liftIO)+import Control.Monad (mapM) import Data.Aeson (FromJSON(..), (.:), Value(..), Object) import Data.ByteString (ByteString) import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BSL import qualified Data.HashMap.Strict as HM import Data.IORef (IORef, newIORef, readIORef, writeIORef)-import Data.Maybe (listToMaybe)-import Data.Monoid ((<>))+import Data.Monoid (Monoid, (<>), mconcat) import Data.Text (Text, unpack) import Data.Traversable (Traversable(traverse))-import Data.Version (Version, parseVersion)+import Data.Version (Version) import qualified Data.Yaml as Yaml import System.FilePath ((</>), (<.>)) import qualified System.IO.Error as IOE import Text.Read (readMaybe)-import Text.ParserCombinators.ReadP (readP_to_S)  import Staversion.Internal.Log   ( Logger, logDebug, logWarn@@ -47,6 +46,10 @@  ( PackageName, PackageSource(..),    ErrorMsg, Resolver  )+import Staversion.Internal.BuildPlan.Hackage+  ( RegisteredVersions, latestVersion,+    fetchPreferredVersions+  ) import Staversion.Internal.BuildPlan.Stackage   ( Disambiguator,     fetchDisambiguator,@@ -55,25 +58,25 @@     PartialResolver(..), ExactResolver,     fetchBuildPlanYAML   )+import Staversion.Internal.BuildPlan.Version (unVersionJSON)  -- | A data structure that keeps a map between package names and their -- versions.-newtype BuildPlan = BuildPlan (HM.HashMap PackageName Version)+newtype BuildPlan = BuildPlan (HM.HashMap PackageName Version) deriving (Monoid)  instance FromJSON BuildPlan where   parseJSON (Object object) = (\p1 p2 -> BuildPlan $ p1 <> p2) <$> core_packages <*> other_packages where     core_packages = parseSysInfo =<< (object .: "system-info")     parseSysInfo (Object o) = parseCorePackages =<< (o .: "core-packages")     parseSysInfo _ = empty-    parseCorePackages (Object o) = traverse (\v -> versionParser =<< parseJSON v) o+    parseCorePackages (Object o) = traverse (\v -> unVersionJSON <$> parseJSON v) o     parseCorePackages _ = empty      other_packages = parsePackages =<< (object .: "packages")     parsePackages (Object o) = traverse parsePackageObject o     parsePackages _ = empty-    parsePackageObject (Object o) = versionParser =<< (o .: "version")+    parsePackageObject (Object o) = unVersionJSON <$> (o .: "version")     parsePackageObject _ = empty-    versionParser = maybe empty return . parseVersionText   parseJSON _ = empty  -- | Stateful manager for 'BuildPlan's.@@ -117,18 +120,31 @@ maybeToLoadM :: ErrorMsg -> Maybe a -> LoadM a maybeToLoadM msg = ExceptT . return . maybe (Left msg) Right +httpManagerM :: BuildPlanManager -> LoadM Manager+httpManagerM = maybeToLoadM "It is not allowed to access network." . manHttpManager+ httpExceptionToLoadM :: String -> LoadM a -> LoadM a httpExceptionToLoadM context action = ExceptT $ (runExceptT action) `catch` handler where   handler :: OurHttpException -> IO (Either ErrorMsg a)   handler e = return $ Left (context ++ ": " ++ show e) -loadBuildPlan :: BuildPlanManager -> PackageSource -> IO (Either ErrorMsg BuildPlan)-loadBuildPlan man (SourceStackage resolver) = runExceptT impl where+loadBuildPlan :: BuildPlanManager+              -> [PackageName] -- ^ package names whose versions the user is interested in.+              -> PackageSource -> IO (Either ErrorMsg BuildPlan)+loadBuildPlan man _ (SourceStackage resolver) = runExceptT impl where   impl = loadBuildPlan_stackageLocalFile man resolver `loggedElse'` do     e_resolver <- tryDisambiguate man =<< getPresolver     loadBuildPlan_stackageLocalFile man (formatResolverString $ PartialExact e_resolver) `loggedElse'` loadBuildPlan_stackageNetwork man e_resolver   getPresolver = maybeToLoadM ("Invalid resolver format for stackage.org: " ++ resolver) $ parseResolverString resolver   loggedElse' = loggedElse $ manLogger man+loadBuildPlan man names SourceHackage = runExceptT impl where+  impl = do+    http_man <- httpManagerM man+    (mconcat . zipWith registeredVersionToBuildPlan names) <$> mapM (doFetch http_man) names+  logDebug' msg = liftIO $ logDebug (manLogger man) msg+  doFetch http_man name = do+    logDebug' ("Ask hackage for the latest version of " ++ unpack name)+    ExceptT $ fetchPreferredVersions http_man name  loadBuildPlan_stackageLocalFile :: BuildPlanManager -> Resolver -> LoadM BuildPlan loadBuildPlan_stackageLocalFile man resolver = ExceptT $ catchJust handleIOError doLoad (return . Left) where@@ -153,7 +169,7 @@     case m_disam of      Just d -> return d      Nothing -> do-       http_man <- maybeToLoadM "It is not allowed to access network." $ manHttpManager bp_man+       http_man <- httpManagerM bp_man        logDebug' "Fetch resolver disambiguator from network..."        got_d <- ExceptT $ fetchDisambiguator http_man        logDebug' "Successfully fetched resolver disambiguator."@@ -163,7 +179,7 @@    loadBuildPlan_stackageNetwork :: BuildPlanManager -> ExactResolver -> LoadM BuildPlan loadBuildPlan_stackageNetwork man e_resolver = do-  http_man <- maybeToLoadM "It is not allowed to access network." $ manHttpManager man+  http_man <- httpManagerM man   liftIO $ logDebug (manLogger man) ("Fetch build plan from network: resolver = " ++ show e_resolver)   yaml_data <- httpExceptionToLoadM ("Downloading build plan failed: " ++ show e_resolver) $ liftIO $ fetchBuildPlanYAML http_man e_resolver   ExceptT $ return $ parseBuildPlanYAML $ BSL.toStrict yaml_data@@ -179,11 +195,11 @@ packageVersion :: BuildPlan -> PackageName -> Maybe Version packageVersion (BuildPlan bp_map) name = HM.lookup name bp_map --- | Parse a version text. There must not be any trailing characters--- after a valid version text.-parseVersionText :: Text -> Maybe Version-parseVersionText = extractResult . (readP_to_S parseVersion) . unpack where-  extractResult = listToMaybe . map fst . filter (\pair -> snd pair == "")- _setDisambiguator :: BuildPlanManager -> Maybe Disambiguator -> IO () _setDisambiguator bp_man = writeIORef (manDisambiguator bp_man)++registeredVersionToBuildPlan :: PackageName -> RegisteredVersions -> BuildPlan+registeredVersionToBuildPlan name rvers = BuildPlan $ HM.fromList $ pairs where+  pairs = case latestVersion rvers of+    Nothing -> []+    Just v -> [(name, v)]
+ src/Staversion/Internal/BuildPlan/Hackage.hs view
@@ -0,0 +1,51 @@+-- |+-- Module: Staversion.Internal.BuildPlan.Hackage+-- Description: (virtual) BuildPlan expressing the latest Hackage+-- Maintainer: Toshio Ito <debug.ito@gmail.com>+--+-- __This is an internal module. End-users should not use it.__+module Staversion.Internal.BuildPlan.Hackage+       ( -- * entry API+         RegisteredVersions,+         fetchPreferredVersions,+         latestVersion,+         -- * low-level API+         parsePreferredVersionsJSON+       ) where++import Control.Applicative ((<$>), empty)+import qualified Control.Exception as Exception+import Data.Aeson (FromJSON(..), Value(..), (.:), eitherDecode)+import qualified Data.ByteString.Lazy as BSL+import Data.List (sort, reverse)+import Data.Text (unpack)+import Data.Version (Version)++import Staversion.Internal.BuildPlan.Version (unVersionJSON)+import Staversion.Internal.Query (ErrorMsg, PackageName)+import Staversion.Internal.HTTP (Manager, fetchURL, OurHttpException)++data RegisteredVersions = RegisteredVersions { regPreferredVersions :: [Version]+                                               -- ^ Sorted list of preferred versions of the package.+                                               -- The head is the latest.+                                             }+                          deriving (Show,Eq,Ord)++instance FromJSON RegisteredVersions where+  parseJSON (Object o) = (RegisteredVersions . reverse . sort . map unVersionJSON) <$> (o .: "normal-version")+  parseJSON _ = empty++parsePreferredVersionsJSON :: BSL.ByteString -> Either ErrorMsg RegisteredVersions+parsePreferredVersionsJSON = either (\e -> Left ("Decoding preferred versions error: " ++ e)) Right . eitherDecode++latestVersion :: RegisteredVersions -> Maybe Version+latestVersion rvers = case regPreferredVersions rvers of+  [] -> Nothing+  (v : _) -> Just v++fetchPreferredVersions :: Manager -> PackageName -> IO (Either ErrorMsg RegisteredVersions)+fetchPreferredVersions man text_name = Exception.handle handler $ parsePreferredVersionsJSON <$> fetchURL man url where+  name = unpack text_name+  url = "http://hackage.haskell.org/package/" ++ name ++ "/preferred.json"+  handler :: OurHttpException -> IO (Either ErrorMsg a)+  handler e = return $ Left ("HTTP error while fetching versions of " ++ name ++ " in hackage: " ++ show e)
+ src/Staversion/Internal/BuildPlan/Version.hs view
@@ -0,0 +1,30 @@+-- |+-- Module: Staversion.Internal.BuildPlan.Version+-- Description: parsing Version+-- Maintainer: Toshio Ito <debug.ito@gmail.com>+--+-- __This is an internal module. End-users should not use it.__+module Staversion.Internal.BuildPlan.Version+       ( parseVersionText,+         VersionJSON(..)+       ) where++import Control.Applicative (empty, pure)+import Data.Aeson (FromJSON(..), Value(..))+import Data.Maybe (listToMaybe)+import Data.Text (Text, unpack)+import Data.Version (Version, parseVersion)+import Text.ParserCombinators.ReadP (readP_to_S)++-- | Parse a version text. There must not be any trailing characters+-- after a valid version text.+parseVersionText :: Text -> Maybe Version+parseVersionText = extractResult . (readP_to_S parseVersion) . unpack where+  extractResult = listToMaybe . map fst . filter (\pair -> snd pair == "")++-- | a wrapper around 'Version' for JSON I/F+newtype VersionJSON = VersionJSON { unVersionJSON :: Version } deriving (Show,Eq,Ord)++instance FromJSON VersionJSON where+  parseJSON (String t) = maybe empty pure $ fmap VersionJSON $ parseVersionText t+  parseJSON _ = empty
src/Staversion/Internal/Command.hs view
@@ -9,7 +9,7 @@          parseCommandArgs        ) where -import Control.Applicative ((<$>), (<*>), optional, some)+import Control.Applicative ((<$>), (<*>), optional, some, (<|>)) import Data.Monoid (mconcat) import Data.Text (pack) import Data.Version (showVersion)@@ -64,19 +64,23 @@                                     ]   build_plan_dir = Opt.strOption                    $ mconcat [ Opt.long "build-plan-dir",-                               Opt.help ( "Directory where build plan YAML files are stored. Default: "-                                          ++ defBuildPlanDir def_comm-                                        ),+                               Opt.help "Directory where build plan YAML files are stored.",                                Opt.metavar "DIR",-                               Opt.value (defBuildPlanDir def_comm)+                               Opt.value (defBuildPlanDir def_comm),+                               Opt.showDefault                              ]-  sources = some $ SourceStackage <$> resolver-  resolver = Opt.strOption+  sources = some $ resolver <|> hackage+  resolver = fmap SourceStackage $ Opt.strOption              $ mconcat [ Opt.long "resolver",                          Opt.short 'r',                          Opt.help "Stackage resolver to search. e.g. \"lts-6.15\"",                          Opt.metavar "RESOLVER_NAME"                        ]+  hackage = Opt.flag' SourceHackage+            $ mconcat [ Opt.long "hackage",+                        Opt.short 'H',+                        Opt.help "Search hackage.org for the latest version."+                      ]   queries = some $ QueryName <$> package   package = fmap pack $ Opt.strArgument             $ mconcat [ Opt.help "Name of package whose version you want to check.",
src/Staversion/Internal/Exec.hs view
@@ -11,7 +11,7 @@  import Control.Applicative ((<$>)) import Data.Function (on)-import Data.List (groupBy)+import Data.List (groupBy, nub) import Data.Text (unpack) import qualified Data.Text.Lazy.IO as TLIO @@ -25,7 +25,7 @@ import Staversion.Internal.Format (formatResultsCabal) import Staversion.Internal.Log (logDebug, logError) import Staversion.Internal.Query-  ( Query(..), Result(..), PackageSource(..),+  ( Query(..), Result(..), PackageSource(..), PackageName,     resultVersionsFromList, ResultVersions,     ErrorMsg   )@@ -42,8 +42,9 @@     fmap concat $ mapM (processQueriesIn bp_man) $ commSources comm   logger = commLogger comm   processQueriesIn bp_man source = do+    queried_names <- fmap (nub . concat) $ mapM getQueriedPackageNames $ commQueries comm     logDebug logger ("Retrieve package source " ++ show source)-    e_build_plan <- loadBuildPlan bp_man source+    e_build_plan <- loadBuildPlan bp_man queried_names source     logBuildPlanResult e_build_plan     return $ map (makeResult source e_build_plan) $ commQueries comm   makeResult source e_build_plan query = case e_build_plan of@@ -57,3 +58,6 @@ searchVersions :: BuildPlan -> Query -> ResultVersions searchVersions build_plan (QueryName package_name) =   resultVersionsFromList [(package_name, packageVersion build_plan package_name)]++getQueriedPackageNames :: Query -> IO [PackageName]+getQueriedPackageNames (QueryName n) = return [n]
src/Staversion/Internal/Query.hs view
@@ -28,6 +28,7 @@  -- | Source of packages. data PackageSource = SourceStackage Resolver -- ^ stackage.+                   | SourceHackage -- ^ hackage (latest)                    deriving (Show,Eq,Ord)  -- | Query for package version(s).@@ -56,3 +57,4 @@ -- | description of a 'PackageSource'. sourceDesc :: PackageSource -> Text sourceDesc (SourceStackage r) = pack r+sourceDesc SourceHackage = "latest in hackage"
staversion.cabal view
@@ -1,5 +1,5 @@ name:                   staversion-version:                0.1.1.0+version:                0.1.2.0 author:                 Toshio Ito <debug.ito@gmail.com> maintainer:             Toshio Ito <debug.ito@gmail.com> license:                BSD3@@ -15,7 +15,8 @@                         test/data/lts-7.0_conpact.yaml,                         test/data/lts-4.2.yaml,                         test/data/lts-2.22_conpact.yaml,-                        test/data/snapshots.json+                        test/data/snapshots.json,+                        test/data/aeson_preferred.json                          homepage:               https://github.com/debug-ito/staversion bug-reports:            https://github.com/debug-ito/staversion/issues@@ -25,9 +26,11 @@   hs-source-dirs:       src   ghc-options:          -Wall -fno-warn-unused-imports   default-extensions:   OverloadedStrings-  other-extensions:     CPP, DeriveDataTypeable+  other-extensions:     CPP, DeriveDataTypeable, GeneralizedNewtypeDeriving   exposed-modules:      Staversion.Internal.BuildPlan,                         Staversion.Internal.BuildPlan.Stackage,+                        Staversion.Internal.BuildPlan.Hackage,+                        Staversion.Internal.BuildPlan.Version,                         Staversion.Internal.Query,                         Staversion.Internal.Command,                         Staversion.Internal.Log,@@ -71,6 +74,8 @@   -- other-extensions:        other-modules:        Staversion.Internal.BuildPlanSpec,                         Staversion.Internal.BuildPlan.StackageSpec,+                        Staversion.Internal.BuildPlan.HackageSpec,+                        Staversion.Internal.BuildPlan.VersionSpec,                         Staversion.Internal.ExecSpec,                         Staversion.Internal.FormatSpec,                         Staversion.Internal.TestUtil
test/NetworkTest.hs view
@@ -1,5 +1,6 @@ module Main (main,spec) where +import Control.Applicative ((<$>)) import qualified Data.ByteString.Lazy as BSL import Network.HTTP.Client (newManager, Manager) import Network.HTTP.Client.TLS (tlsManagerSettings)@@ -13,13 +14,19 @@     loadBuildPlan,     packageVersion   )+import Staversion.Internal.BuildPlan.Hackage (fetchPreferredVersions, latestVersion) import Staversion.Internal.BuildPlan.Stackage   ( fetchDisambiguator,     fetchBuildPlanYAML,     PartialResolver(..), ExactResolver(..)   )+import Staversion.Internal.Command (Command(..))+import Staversion.Internal.Exec (processCommand) import Staversion.Internal.Log (defaultLogger, Logger(loggerThreshold))-import Staversion.Internal.Query (PackageSource(..))+import Staversion.Internal.Query+ ( PackageSource(..), ErrorMsg, Query(..), Result(..),+   resultVersionsToList+ )  main :: IO () main = hspec spec@@ -28,6 +35,8 @@ spec = do   spec_Stackage   spec_BuildPlan+  spec_Hackage+  spec_Exec  spec_Stackage:: Spec spec_Stackage = describe "BuildPlan.Stackage" $ beforeAll makeManager $ do@@ -48,15 +57,56 @@ makeManager :: IO Manager makeManager = newManager tlsManagerSettings +quietLogger :: Logger+quietLogger = defaultLogger { loggerThreshold = Nothing }++expectRight :: String -> Either ErrorMsg a -> IO a+expectRight msg_head = either (\err -> error $ msg_head ++ err) return++isJustAnd :: Maybe a -> (a -> Bool) -> Bool+isJustAnd m p = maybe False p m+ spec_BuildPlan :: Spec spec_BuildPlan = describe "BuildPlan" $ do   describe "loadBuildPlan from Stackage" $ do     it "disambiguates LTS version and fetches a valid BuildPlan" $ do-      let logger = defaultLogger { loggerThreshold = Nothing }-      bp_man <- newBuildPlanManager "." logger True-      bp <- loadBuildPlan bp_man (SourceStackage "lts-5") >>= \ret -> case ret of-        Right bp -> return bp-        Left error_msg -> error ("loadBuildPlan failed: " ++ error_msg)+      bp_man <- newBuildPlanManager "." quietLogger True+      bp <- expectRight "loadBuildPlan failed: " =<< loadBuildPlan bp_man [] (SourceStackage "lts-5")       packageVersion bp "base" `shouldBe` Just (ver [4,8,2,0])       packageVersion bp "bytestring" `shouldBe` Just (ver [0,10,6,0])       packageVersion bp "conduit" `shouldBe` Just (ver [1,2,6,6])+  describe "loadBuildPlan from Hackage" $ do+    it "fetches BuildPlan for queried packages" $ do+      bp_man <- newBuildPlanManager "." quietLogger True+      bp <- expectRight "loadBuildPlan failed: " =<< loadBuildPlan bp_man ["base", "lens", "transformers"] SourceHackage+      packageVersion bp "base" `shouldSatisfy` (`isJustAnd` (>= ver [4,9,0,0]))+      packageVersion bp "lens" `shouldSatisfy` (`isJustAnd` (>= ver [4,15,1]))+      packageVersion bp "transformers" `shouldSatisfy` (`isJustAnd` (>= ver [0,5,2,0]))++spec_Hackage :: Spec+spec_Hackage = describe "BuildPlan.Hackage" $ do+  describe "fetchPreferredVersions" $ do+    it "fetches a non-empty latestVersion" $ do+      man <- makeManager+      ret <- fmap latestVersion <$> fetchPreferredVersions man "http-client"+      case ret of+       Right (Just v) -> v `shouldSatisfy` (>= ver [0,5,3,3])+       _ -> expectationFailure ("Unexpected return: " ++ show ret)++spec_Exec :: Spec+spec_Exec = describe "Exec" $ describe "processCommand" $ do+  specify "search hackage" $ do+    let comm = Command { commBuildPlanDir = ".",+                         commLogger = quietLogger,+                         commSources = [SourceHackage],+                         commQueries = [QueryName "base"],+                         commAllowNetwork = True+                       }+    [ret] <- processCommand comm+    resultIn ret `shouldBe` SourceHackage+    resultFor ret `shouldBe` QueryName "base"+    [(got_name, Just got_version)] <- resultVersionsToList <$> expectRight "processCommand error" (resultVersions ret)+    got_name `shouldBe` "base"+    got_version `shouldSatisfy` (>= ver [4,9,0,0]) +    +    
+ test/Staversion/Internal/BuildPlan/HackageSpec.hs view
@@ -0,0 +1,22 @@+module Staversion.Internal.BuildPlan.HackageSpec (main,spec) where++import qualified Data.ByteString.Lazy as BSL+import System.FilePath ((</>))+import Test.Hspec++import Staversion.Internal.TestUtil (ver)++import Staversion.Internal.BuildPlan.Hackage+  ( parsePreferredVersionsJSON,+    latestVersion+  )++main :: IO ()+main = hspec spec++spec :: Spec+spec = describe "parsePreferredVersionsJSON" $ do+  it "should parse aeson_preferred.json" $ do+    yaml_data <- BSL.readFile ("test" </> "data" </> "aeson_preferred.json")+    rvers <- either (\e -> error ("parse error: " ++ e)) return $ parsePreferredVersionsJSON yaml_data+    latestVersion rvers `shouldBe` Just (ver [1,0,2,1])
+ test/Staversion/Internal/BuildPlan/VersionSpec.hs view
@@ -0,0 +1,21 @@+module Staversion.Internal.BuildPlan.VersionSpec (main,spec) where++import Data.Text (pack)+import Data.Version (Version(..))+import Test.Hspec++import Staversion.Internal.BuildPlan.Version (parseVersionText)++main :: IO ()+main = hspec spec++spec :: Spec+spec = parseVersionText_spec++parseVersionText_spec :: Spec+parseVersionText_spec = describe "parseVersionText" $ do+  spec_v "0.1.0.6" $ Just (Version [0,1,0,6] [])+  spec_v "10.11" $ Just (Version [10,11] [])+  where+    spec_v input_v expected = specify input_v $ do+      parseVersionText (pack input_v) `shouldBe` expected
test/Staversion/Internal/BuildPlanSpec.hs view
@@ -11,7 +11,6 @@   ( BuildPlan,      loadBuildPlanYAML,      packageVersion,-    parseVersionText,     BuildPlanManager,     newBuildPlanManager,     _setDisambiguator,@@ -27,18 +26,9 @@  spec :: Spec spec = do-  parseVersionText_spec   packageVersion_spec   loadBuildPlan_spec -parseVersionText_spec :: Spec-parseVersionText_spec = describe "parseVersionText" $ do-  spec_v "0.1.0.6" $ Just (Version [0,1,0,6] [])-  spec_v "10.11" $ Just (Version [10,11] [])-  where-    spec_v input_v expected = specify input_v $ do-      parseVersionText (pack input_v) `shouldBe` expected- packageVersion_spec :: Spec packageVersion_spec = describe "packageVersion" $ do   forBuildPlan "conpact_build_plan" $ \loader -> do@@ -83,5 +73,5 @@     let disam (PartialLTSLatest) = Just $ ExactLTS 4 2         disam _ = Nothing     bp_man <- mockBuildPlanManager disam-    bp <- either (\e -> error ("Error: " ++ e)) return =<< loadBuildPlan bp_man (SourceStackage "lts")+    bp <- either (\e -> error ("Error: " ++ e)) return =<< loadBuildPlan bp_man [] (SourceStackage "lts")     packageVersion bp "base" `shouldBe` (Just $ Version [4,8,2,0] [])
+ test/data/aeson_preferred.json view
@@ -0,0 +1,1 @@+{"normal-version":["1.0.2.1","1.0.2.0","1.0.1.0","1.0.0.0","0.11.2.1","0.11.2.0","0.11.1.4","0.11.1.3","0.11.1.2","0.11.1.1","0.11.1.0","0.11.0.0","0.9.0.1","0.9.0.0","0.8.1.1","0.8.1.0","0.8.0.2","0.7.0.6","0.7.0.4","0.6.2.1","0.6.2.0","0.6.1.0","0.6.0.2","0.6.0.1","0.6.0.0","0.5.0.0","0.4.0.1","0.4.0.0","0.3.2.14","0.3.2.13","0.3.2.12","0.3.2.11","0.3.2.10","0.3.2.9","0.3.2.8","0.3.2.7","0.3.2.6","0.3.2.5","0.3.2.4","0.3.2.3","0.3.2.2","0.3.2.1","0.3.2.0","0.3.1.1","0.3.1.0","0.3.0.0","0.2.0.0","0.1.0.0"],"deprecated-version":["0.10.0.0","0.8.0.1","0.8.0.0","0.7.0.5","0.7.0.3","0.7.0.2","0.7.0.1","0.7.0.0"]}