packages feed

staversion (empty) → 0.1.0.0

raw patch · 21 files changed

+2070/−0 lines, 21 filesdep +aesondep +basedep +bytestringsetup-changed

Dependencies added: aeson, base, bytestring, directory, filepath, hspec, optparse-applicative, staversion, text, unordered-containers, yaml

Files

+ ChangeLog.md view
@@ -0,0 +1,5 @@+# Revision history for staversion++## 0.1.0.0  -- 2016-10-16++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2016, Toshio Ito++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Toshio Ito nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,41 @@+# staversion++![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 --resolver lts-4.2 conduit+    ------ lts-4.2+    conduit ==1.2.6.1+    +    $ staversion --resolver lts-4.2 --resolver lts-7.0 conduit+    ------ lts-4.2+    conduit ==1.2.6.1+    +    ------ lts-7.0+    conduit ==1.2.7+    +    $ staversion --resolver lts-4.2 --resolver lts-7.0 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++Currently staversion reads build plan YAML files that are stored locally in your computer.+++## TODO++- Fetch build plan YAML files from github.com+- Cache build plans in some local storage (SQLite?)+- Expand major version resolvers (lts-X) into full resolvers (lts-X.YY)+- 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.++## Author++Toshio Ito <debug.ito@gmail.com>
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ app/Main.hs view
@@ -0,0 +1,4 @@+module Main+       (main) where++import Staversion.Internal.Exec (main)
+ src/Staversion/Internal/BuildPlan.hs view
@@ -0,0 +1,65 @@+-- |+-- Module: Staversion.Internal.BuildPlan+-- Description:  Handle build plan YAML files.+-- Maintainer: Toshio Ito <debug.ito@gmail.com>+--+-- __This is an internal module. End-users should not use it.__+module Staversion.Internal.BuildPlan+       ( PackageName,+         BuildPlan,+         loadBuildPlanYAML,+         packageVersion,+         parseVersionText+       ) where++import Control.Applicative (empty, (<$>), (<*>))+import Control.Exception (throwIO)+import Data.Aeson (FromJSON(..), (.:), Value(..), Object)+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+import qualified Data.HashMap.Strict as HM+import Data.Maybe (listToMaybe)+import Data.Monoid ((<>))+import Data.Text (Text, unpack)+import Data.Traversable (Traversable(traverse))+import Data.Version (Version, parseVersion)+import qualified Data.Yaml as Yaml+import Text.Read (readMaybe)+import Text.ParserCombinators.ReadP (readP_to_S)++import Staversion.Internal.Query (PackageName)++-- | A data structure that keeps a map between package names and their+-- versions.+newtype BuildPlan = BuildPlan (HM.HashMap PackageName Version)++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 _ = empty++    other_packages = parsePackages =<< (object .: "packages")+    parsePackages (Object o) = traverse parsePackageObject o+    parsePackages _ = empty+    parsePackageObject (Object o) = versionParser =<< (o .: "version")+    parsePackageObject _ = empty+    versionParser = maybe empty return . parseVersionText+  parseJSON _ = empty+++-- | Load a 'BuildPlan' from a file.+loadBuildPlanYAML :: FilePath -> IO BuildPlan+loadBuildPlanYAML yaml_file = (toException . Yaml.decodeEither') =<< BS.readFile yaml_file where -- TODO: make it memory-efficient!+  toException = either (throwIO) return++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 == "")
+ src/Staversion/Internal/Command.hs view
@@ -0,0 +1,95 @@+-- |+-- Module: Staversion.Internal.Command+-- Description: Command from the user.+-- Maintainer: Toshio Ito <debug.ito@gmail.com>+--+-- __This is an internal module. End-users should not use it.__+module Staversion.Internal.Command+       ( Command(..),+         parseCommandArgs+       ) where++import Control.Applicative ((<$>), (<*>), optional, some)+import Data.Monoid (mconcat)+import Data.Text (pack)+import Data.Version (showVersion)+import qualified Options.Applicative as Opt+import qualified Paths_staversion as MyInfo+import System.Directory (getHomeDirectory)+import System.FilePath ((</>))++import Staversion.Internal.Log+  ( LogLevel(..), Logger(loggerThreshold), defaultLogger+  )+import Staversion.Internal.Query+  ( Resolver,+    PackageName,+    Query(..),+    PackageSource(..)+  )++-- | Command from the user.+data Command =+  Command { commBuildPlanDir :: FilePath,+            -- ^ path to the directory where build plan files are stored.+            commLogger :: Logger,+            -- ^ the logger+            commSources :: [PackageSource],+            -- ^ package sources to search+            commQueries :: [Query]+            -- ^ package queries+          } deriving (Show,Eq)++-- | Default values for 'Command'.+data DefCommand = DefCommand { defBuildPlanDir :: FilePath+                             } deriving (Show,Eq,Ord)++defCommand :: IO DefCommand+defCommand = DefCommand <$> def_build_plan_dir where+  def_build_plan_dir = do+    home <- getHomeDirectory+    return $ home </> ".stack" </> "build-plan"+++commandParser :: DefCommand -> Opt.Parser Command+commandParser def_comm = Command <$> build_plan_dir <*> logger <*> sources <*> queries where+  logger = makeLogger <$> is_verbose+  makeLogger True = defaultLogger { loggerThreshold = Just LogDebug }+  makeLogger False = defaultLogger+  is_verbose = Opt.switch $ mconcat [ Opt.long "verbose",+                                      Opt.short 'v',+                                      Opt.help "Verbose messages."+                                    ]+  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.metavar "DIR",+                               Opt.value (defBuildPlanDir def_comm)+                             ]+  sources = some $ SourceStackage <$> resolver+  resolver = Opt.strOption+             $ mconcat [ Opt.long "resolver",+                         Opt.short 'r',+                         Opt.help "Stackage resolver to search. e.g. \"lts-6.15\"",+                         Opt.metavar "RESOLVER_NAME"+                       ]+  queries = some $ QueryName <$> package+  package = fmap pack $ Opt.strArgument+            $ mconcat [ Opt.help "Name of package whose version you want to check.",+                        Opt.metavar "PACKAGE_NAME"+                      ]++programDescription :: Opt.Parser a -> Opt.ParserInfo a+programDescription parser =+  Opt.info (Opt.helper <*> parser)+  $ mconcat [ Opt.fullDesc,+              Opt.progDesc ( "Look for version numbers for Haskell packages in specific stackage resolvers"+                             ++ " (or possibly other package sources)"+                           ),+              Opt.footer ("Version: " ++ (showVersion MyInfo.version))+            ]++parseCommandArgs :: IO Command+parseCommandArgs = Opt.execParser . programDescription . commandParser =<< defCommand
+ src/Staversion/Internal/Exec.hs view
@@ -0,0 +1,72 @@+-- |+-- Module: Staversion.Internal.Exec+-- Description: executable+-- Maintainer: Toshio Ito <debug.ito@gmail.com>+--+-- __This is an internal module. End-users should not use it.__+module Staversion.Internal.Exec+       ( main,+         processCommand+       ) where++import Control.Applicative ((<$>))+import Control.Exception (catchJust, IOException)+import Data.Function (on)+import Data.List (groupBy)+import Data.Text (unpack)+import qualified Data.Text.Lazy.IO as TLIO+import System.FilePath ((</>), (<.>))+import qualified System.IO.Error as IOE++import Staversion.Internal.BuildPlan+  ( BuildPlan, loadBuildPlanYAML, packageVersion+  )+import Staversion.Internal.Command+  ( parseCommandArgs,+    Command(..)+  )+import Staversion.Internal.Format (formatResultsCabal)+import Staversion.Internal.Log (logDebug, logWarn)+import Staversion.Internal.Query+  ( Query(..), Result(..), PackageSource(..),+    resultVersionsFromList, ResultVersions,+    ErrorMsg+  )++main :: IO ()+main = do+  comm <- parseCommandArgs+  (TLIO.putStr . formatResultsCabal) =<< (processCommand comm)++processCommand :: Command -> IO [Result]+processCommand comm = fmap concat $ mapM processQueriesIn $ commSources comm where+  logger = commLogger comm+  processQueriesIn source = do+    logDebug logger ("Retrieve package source " ++ show source)+    e_build_plan <- loadBuildPlan comm 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+    Left error_msg -> Result { resultIn = source, resultFor = query, resultVersions = Left error_msg }+    Right build_plan -> Result { resultIn = source, resultFor = query,+                                 resultVersions = Right $ searchVersions build_plan query+                               }+  logBuildPlanResult (Right _) = logDebug logger ("Successfully retrieved build plan.")+  logBuildPlanResult (Left error_msg) = logWarn logger ("Failed to load build plan: " ++ error_msg)++loadBuildPlan ::  Command -> PackageSource -> IO (Either ErrorMsg BuildPlan)+loadBuildPlan comm source@(SourceStackage resolver) = catchJust handleIOError (Right <$> doLoad) (return . Left) where+  yaml_file = commBuildPlanDir comm </> resolver <.> "yaml"+  doLoad = do+    logDebug (commLogger comm) ("Read " ++ yaml_file ++ " for build plan.")+    loadBuildPlanYAML yaml_file+  handleIOError :: IOException -> Maybe ErrorMsg+  handleIOError e | IOE.isDoesNotExistError e = Just $ makeErrorMsg e (yaml_file ++ " not found.")+                  | IOE.isPermissionError e = Just $ makeErrorMsg e ("you cannot open " ++ yaml_file ++ ".")+                  | otherwise = Just $ makeErrorMsg e ("some error.")+  makeErrorMsg exception body = "Loading build plan for package source " ++ show source ++ " failed: " ++ body ++ "\n" ++ show exception+++searchVersions :: BuildPlan -> Query -> ResultVersions+searchVersions build_plan (QueryName package_name) =+  resultVersionsFromList [(package_name, packageVersion build_plan package_name)]
+ src/Staversion/Internal/Format.hs view
@@ -0,0 +1,62 @@+-- |+-- Module: Staversion.Internal.Format+-- Description: formatting Result output.+-- Maintainer: Toshio Ito <debug.ito@gmail.com>+--+-- __This is an internal module. End-users should not use it.__+module Staversion.Internal.Format+       ( formatResultsCabal+       ) where++import Data.Function (on)+import Data.List (intersperse)+import Data.Monoid (mempty, mconcat, (<>))+import qualified Data.Text.Lazy as TL+import Data.Text.Lazy.Builder (Builder, toLazyText, fromText, fromString)+import Data.Version (showVersion)++import Staversion.Internal.Query+  ( Result(..), Query(..),+    sourceDesc,+    ResultVersions,+    resultVersionsToList+  )++-- | format 'Result's like it's in build-depends in .cabal files.+formatResultsCabal :: [Result] -> TL.Text+formatResultsCabal = toLazyText . mconcat . map formatGroupedResultsCabal . groupAllPreservingOrderBy ((==) `on` resultIn)++groupAllPreservingOrderBy :: (a -> a -> Bool) -> [a] -> [[a]]+groupAllPreservingOrderBy sameGroup = map snd  . foldr f [] where+  f item acc = update [] acc where+    update heads [] = (item, [item]) : heads+    update heads (cur@(cur_item, cur_list) : rest) =+      if sameGroup item cur_item+      then heads ++ ( (cur_item, item : cur_list) : rest )+      else update (heads ++ [cur]) rest++formatGroupedResultsCabal :: [Result] -> Builder+formatGroupedResultsCabal [] = mempty+formatGroupedResultsCabal results@(head_ret : _) = header <> (concatLines $ single_result_output =<< results) where+  header = "------ " <> (fromText $ sourceDesc $ resultIn head_ret) <> "\n"+  single_result_output ret = case resultVersions ret of+    Left _ -> [Left $ error_result ret]+    Right versions -> formatVersionsCabal (resultFor ret) versions+  error_result ret = case resultFor ret of+    QueryName query_name -> "-- " <> fromText query_name <> " ERROR"+  concatLines ebuilder_lines = (mconcat $ intersperse "\n" $ map (either id id) $ tailCommas ebuilder_lines) <> "\n\n"+  tailCommas = fst . foldr f ([], False) where+    -- flag: True if it has already encountered the last Right element in the list.+    f eb (ret, flag) = let (next_e, next_flag) = getNext ret flag eb+                       in (next_e:ret, next_flag)+    getNext [] flag e@(Left _) = (e, flag)+    getNext _ flag (Left b) = (Left (b <> ","), flag)+    getNext _ False e@(Right _) = (e, True)+    getNext _ True (Right b) = (Right (b <> ","), True)++formatVersionsCabal :: Query -> ResultVersions -> [Either Builder Builder]+formatVersionsCabal (QueryName _) rvers = map format $ resultVersionsToList rvers where+  format (name, mver) = case mver of+    Nothing -> Left $ "-- " <> fromText name <> " N/A"+    Just ver -> Right $ fromText name <> " ==" <> (fromString $ showVersion ver)+
+ src/Staversion/Internal/Log.hs view
@@ -0,0 +1,57 @@+-- |+-- Module: Staversion.Internal.Log+-- Description: types and functions about logging+-- Maintainer: Toshio Ito <debug.ito@gmail.com>+--+-- +module Staversion.Internal.Log+       ( LogLevel(..),+         Logger(loggerThreshold),+         defaultLogger,+         putLog,+         logDebug,+         logInfo,+         logWarn+       ) where++import Control.Monad (when)+import System.IO (Handle, stderr, hPutStrLn)++data LogLevel = LogDebug+              | LogInfo+              | LogWarn+              | LogError+              deriving (Show,Eq,Ord,Enum,Bounded)++data Logger = Logger { loggerThreshold :: Maybe LogLevel,+                       -- ^ If 'Nothing', logging is disabled.+                       loggerHandle :: Handle+                     } deriving (Show,Eq)++defaultLogger :: Logger+defaultLogger = Logger { loggerThreshold = Just LogInfo,+                         loggerHandle = stderr+                       }++toLabel :: LogLevel -> String+toLabel l = case l of+  LogDebug -> "[debug]"+  LogInfo ->  "[info]"+  LogWarn ->  "[warn]"+  LogError -> "[error]"++putLog :: Logger -> LogLevel -> String -> IO ()+putLog logger level raw_msg = when (fmap (level >=) mthreshold == Just True) $ hPutStrLn log_handle msg where+  mthreshold = loggerThreshold logger+  log_handle = loggerHandle logger+  msg = toLabel level ++ " " ++ raw_msg++logDebug :: Logger -> String -> IO ()+logDebug = flip putLog $ LogDebug++logInfo :: Logger -> String -> IO ()+logInfo = flip putLog $ LogInfo++logWarn :: Logger -> String -> IO ()+logWarn = flip putLog $ LogWarn+
+ src/Staversion/Internal/Query.hs view
@@ -0,0 +1,58 @@+-- |+-- Module: Staversion.Internal.Query+-- Description: Query, Result and related symbols.+-- Maintainer: Toshio Ito <debug.ito@gmail.com>+--+-- __This is an internal module. End-users should not use it.__+module Staversion.Internal.Query+       ( PackageName,+         Resolver,+         PackageSource(..),+         Query(..),+         ErrorMsg,+         Result(..),+         ResultVersions,+         resultVersionsFromList,+         resultVersionsToList,+         sourceDesc+       ) where++import qualified Data.HashMap.Strict as HM+import Data.Text (Text, pack)+import Data.Version (Version)++type PackageName = Text++-- | Resolver name at stackage like "lts-4.1".+type Resolver = String++-- | Source of packages.+data PackageSource = SourceStackage Resolver -- ^ stackage.+                   deriving (Show,Eq,Ord)++-- | Query for package version(s).+data Query = QueryName PackageName+           deriving (Show,Eq,Ord)++type ErrorMsg = String++-- | Result for a query.+data Result = Result { resultIn :: PackageSource,+                       resultFor :: Query,+                       resultVersions :: Either ErrorMsg ResultVersions+                     } deriving (Show,Eq)+++-- | The obtained version map.+newtype ResultVersions = ResultVersions (HM.HashMap PackageName (Maybe Version))+                       deriving (Show,Eq)++resultVersionsFromList :: [(PackageName, Maybe Version)] -> ResultVersions+resultVersionsFromList = ResultVersions . HM.fromList++resultVersionsToList :: ResultVersions -> [(PackageName, Maybe Version)]+resultVersionsToList (ResultVersions m) = HM.toList m++-- | description of a 'PackageSource'.+sourceDesc :: PackageSource -> Text+sourceDesc (SourceStackage r) = pack r
+ staversion.cabal view
@@ -0,0 +1,72 @@+name:                   staversion+version:                0.1.0.0+author:                 Toshio Ito <debug.ito@gmail.com>+maintainer:             Toshio Ito <debug.ito@gmail.com>+license:                BSD3+license-file:           LICENSE+synopsis:               What version is the package X in stackage lts-Y.ZZ?+description:            A command-line tool to look for version numbers for Haskell packages in specific stackage resolvers. See README.md+category:               Development+cabal-version:          >= 1.10+build-type:             Simple+extra-source-files:     README.md, ChangeLog.md,+                        test/data/conpact_build_plan.yaml,+                        -- Cabal's wild-card (*) doesn't match periods (.)+                        test/data/lts-7.0_conpact.yaml,+                        test/data/lts-4.2.yaml,+                        test/data/lts-2.22_conpact.yaml+                        +homepage:               https://github.com/debug-ito/staversion+bug-reports:            https://github.com/debug-ito/staversion/issues++library+  default-language:     Haskell2010+  hs-source-dirs:       src+  ghc-options:          -Wall -fno-warn-unused-imports+  default-extensions:   OverloadedStrings+  -- other-extensions:     +  exposed-modules:      Staversion.Internal.BuildPlan,+                        Staversion.Internal.Query,+                        Staversion.Internal.Command,+                        Staversion.Internal.Log,+                        Staversion.Internal.Exec,+                        Staversion.Internal.Format+  other-modules:        Paths_staversion+  build-depends:        base >=4.6 && <4.10,+                        unordered-containers >=0.2.3 && <0.3,+                        aeson >=0.8.0 && <1.1,+                        text >=0.11.3 && <1.3,+                        bytestring >=0.10.0 && <0.11,+                        yaml >=0.8.3 && <0.9,+                        filepath >=1.3.0 && <1.5,+                        directory >=1.2.0 && <1.3,+                        optparse-applicative >=0.11.0 && <0.14++executable staversion+  default-language:     Haskell2010+  hs-source-dirs:       app+  main-is:              Main.hs+  ghc-options:          -Wall -fno-warn-unused-imports -rtsopts -threaded "-with-rtsopts=-N"+  -- other-modules:        +  -- default-extensions:   +  -- other-extensions:     +  build-depends:        base, staversion++test-suite spec+  type:                 exitcode-stdio-1.0+  default-language:     Haskell2010+  hs-source-dirs:       test+  ghc-options:          -Wall -fno-warn-unused-imports "-with-rtsopts=-M512m"+  main-is:              Spec.hs+  default-extensions:   OverloadedStrings+  -- other-extensions:     +  other-modules:        Staversion.Internal.BuildPlanSpec,+                        Staversion.Internal.ExecSpec,+                        Staversion.Internal.FormatSpec,+                        Staversion.Internal.TestUtil+  build-depends:        base, staversion, text, filepath,+                        hspec >=2.1.7 && <2.4+                        +source-repository head+  type:                 git+  location:             https://github.com/debug-ito/staversion.git
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ test/Staversion/Internal/BuildPlanSpec.hs view
@@ -0,0 +1,58 @@+module Staversion.Internal.BuildPlanSpec (main,spec) where++import Data.Text (Text, pack)+import Data.Version (Version(..))+import System.FilePath ((</>), (<.>))+import Test.Hspec++import Staversion.Internal.BuildPlan+  ( PackageName,+    BuildPlan, +    loadBuildPlanYAML, +    packageVersion,+    parseVersionText+  )++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+  parseVersionText_spec+  packageVersion_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+    specify "drawille -> 0.1.0.6" $ do+      loadVersion "drawille" loader `shouldReturn` Just (Version [0,1,0,6] [])+    specify "unknown -> Nothing" $ do+      loadVersion "unknown" loader `shouldReturn` Nothing+    specify "ghc -> 7.10.3" $ do+      loadVersion "ghc" loader `shouldReturn` Just (Version [7,10,3] [])+    specify "base -> 4.8.2.0" $ do+      loadVersion "base" loader `shouldReturn` Just (Version [4,8,2,0] [])++  forBuildPlan "lts-4.2" $ \loader -> do+    specify "conduit -> 1.2.6.1" $ do+      loadVersion "conduit" loader `shouldReturn` Just (Version [1,2,6,1] [])+    specify "transformers -> 0.4.2.0" $ do+      loadVersion "transformers" loader `shouldReturn` Just (Version [0,4,2,0] [])+++forBuildPlan :: String -> (IO BuildPlan -> Spec) -> Spec+forBuildPlan build_plan_base testWith = describe build_plan_base (testWith loader) where+  loader = loadBuildPlanYAML ("test" </> "data" </> build_plan_base <.> "yaml")++loadVersion :: PackageName -> IO BuildPlan -> IO (Maybe Version)+loadVersion package_name loader = do+  plan <- loader+  return $ packageVersion plan package_name
+ test/Staversion/Internal/ExecSpec.hs view
@@ -0,0 +1,81 @@+module Staversion.Internal.ExecSpec (main,spec) where++import Data.Version (Version(Version))+import System.FilePath ((</>))+import Test.Hspec++import Staversion.Internal.Command (Command(..))+import Staversion.Internal.Exec (processCommand)+import Staversion.Internal.Query+  ( PackageName,+    Query(..),+    PackageSource(..),+    Result(..),+    ResultVersions,+    resultVersionsFromList,+    ErrorMsg+  )+import Staversion.Internal.Log (defaultLogger, Logger(loggerThreshold), LogLevel(LogError))++import Staversion.Internal.TestUtil (ver, rvers)++main :: IO ()+main = hspec spec++spec :: Spec+spec = describe "processCommand" $ do+  specify "QueryName, SourceStackage, hit" $ do+    singleCase (SourceStackage "conpact_build_plan") (QueryName "drawille")+      (Right $ rvers [("drawille", Just $ ver [0,1,0,6])])+  specify "QueryName, SourceStackage, miss" $ do+    singleCase (SourceStackage "conpact_build_plan") (QueryName "unknown")+      (Right $ rvers [("unknown", Nothing)])+  specify "QueryName, SourceStackage, source not found" $ do+    singleCase' (SourceStackage "unknown") (QueryName "drawille") $ \got -> case got of+      Right _ -> expectationFailure "it should fail"+      Left msg -> do+        msg `shouldContain` "unknown.yaml"+        msg `shouldContain` "not found"+  specify "QueryName, SourceStackage, full-mesh" $ do+    let src2 = SourceStackage "lts-2.22_conpact"+        src7 = SourceStackage "lts-7.0_conpact"+        qc = QueryName "conduit"+        qa = QueryName "aeson"+        comm = baseCommand { commSources = [src2, src7], commQueries = [qc, qa] }+        expected = [ Result { resultIn = src2, resultFor = qc,+                              resultVersions = Right $ rvers [("conduit", Just $ ver [1,2,5])]+                            },+                     Result { resultIn = src2, resultFor = qa,+                              resultVersions = Right $ rvers [("aeson", Just $ ver [0,8,0,2])]+                            },+                     Result { resultIn = src7, resultFor = qc,+                              resultVersions = Right $ rvers [("conduit", Just $ ver [1,2,7])]+                            },+                     Result { resultIn = src7, resultFor = qa,+                              resultVersions = Right $ rvers [("aeson", Just $ ver [0,11,2,1])]+                            }+                   ]+    got <- processCommand comm+    got `shouldBe` expected+        ++singleCase :: PackageSource -> Query -> Either ErrorMsg ResultVersions -> IO ()+singleCase src query exp_ret_vers = singleCase' src query (`shouldBe` exp_ret_vers)++singleCase' :: PackageSource -> Query -> (Either ErrorMsg ResultVersions -> IO a) -> IO a+singleCase' src query checker = do+  [got_ret] <- processCommand comm+  resultIn got_ret `shouldBe` src+  resultFor got_ret `shouldBe` query+  checker $ resultVersions got_ret+  where+    comm =  baseCommand { commSources = [src],+                          commQueries = [query]+                        }++baseCommand :: Command+baseCommand = Command { commBuildPlanDir = "test" </> "data",+                        commLogger = defaultLogger { loggerThreshold = Nothing },+                        commSources = [],+                        commQueries = []+                      }
+ test/Staversion/Internal/FormatSpec.hs view
@@ -0,0 +1,84 @@+module Staversion.Internal.FormatSpec (main,spec) where++import Data.Monoid ((<>))+import Test.Hspec++import Staversion.Internal.Format (formatResultsCabal)+import Staversion.Internal.Query+  ( Result(..), PackageSource(..), Query(..),+    Resolver, PackageName+  )++import Staversion.Internal.TestUtil (ver, rvers)+       +++main :: IO ()+main = hspec spec++spec :: Spec+spec = describe "formatResultsCabal" $ do+  it "should return empty text for empty list" $ do+    formatResultsCabal [] `shouldBe` ""+  it "should format a Result in a Cabal way" $ do+    let input = [ Result { resultIn = SourceStackage "lts-6.10",+                           resultFor = QueryName "hoge",+                           resultVersions = Right $ rvers [("hoge", Just $ ver [3,4,5])]+                         }+                ]+        expected = ( "------ lts-6.10\n"+                     <> "hoge ==3.4.5\n"+                     <> "\n"+                   )+    formatResultsCabal input `shouldBe` expected+  +  it "should group Results by PackageSource with preserved order" $ do+    let input = [ simpleResult "source_c" "hoge" [0,5,7],+                  simpleResult "source_a" "hoge" [1,0,0],+                  simpleResult "source_b" "foobar" [0,2,5,3],+                  simpleResult "source_b" "hoge" [1,2,0],+                  simpleResult "source_a" "quux" [300,5],+                  simpleResult "source_a" "foobar" [0,3,2],+                  simpleResult "source_b" "quux" [299,10]+                ]+        expected = ( "------ source_c\n"+                     <> "hoge ==0.5.7\n"+                     <> "\n"+                     <> "------ source_a\n"+                     <> "hoge ==1.0.0,\n"+                     <> "quux ==300.5,\n"+                     <> "foobar ==0.3.2\n"+                     <> "\n"+                     <> "------ source_b\n"+                     <> "foobar ==0.2.5.3,\n"+                     <> "hoge ==1.2.0,\n"+                     <> "quux ==299.10\n"+                     <> "\n"+                   )+    formatResultsCabal input `shouldBe` expected+  it "should not put comma at the last non-N/A entry even if it is followed by N/A entries"  $ do+    let input = [ simpleResult "s" "hoge" [1,0,0],+                  simpleResult "s" "not-found-1" [],+                  simpleResult "s" "foobar" [2,0,0],+                  simpleResult "s" "not-found-2" [],+                  simpleResult "s" "not-found-3" []+                ]+        expected = ( "------ s\n"+                     <> "hoge ==1.0.0,\n"+                     <> "-- not-found-1 N/A,\n"+                     <> "foobar ==2.0.0\n"+                     <> "-- not-found-2 N/A,\n"+                     <> "-- not-found-3 N/A\n"+                     <> "\n"+                   )+    formatResultsCabal input `shouldBe` expected++simpleResult :: Resolver -> PackageName -> [Int] -> Result+simpleResult res name vs = Result { resultIn = SourceStackage res,+                                    resultFor = QueryName name,+                                    resultVersions = Right $ rvers [(name, mversion)]+                                  }+  where+    mversion = case vs of+      [] -> Nothing+      _ -> Just $ ver vs
+ test/Staversion/Internal/TestUtil.hs view
@@ -0,0 +1,13 @@+module Staversion.Internal.TestUtil+       ( ver, rvers+       ) where++import Data.Version (Version(..))+import Staversion.Internal.Query (PackageName, ResultVersions, resultVersionsFromList)++ver :: [Int] -> Version+ver vs = Version vs []++rvers :: [(PackageName, Maybe Version)] -> ResultVersions+rvers = resultVersionsFromList+
+ test/data/conpact_build_plan.yaml view
@@ -0,0 +1,97 @@+github-users:+  yesodweb:+  - snoyberg+system-info:+  core-packages:+    ghc: '7.10.3'+    hoopl: '3.10.0.2'+    bytestring: '0.10.6.0'+    unix: '2.7.1.0'+    base: '4.8.2.0'+    time: '1.5.0.1'+    hpc: '0.6.0.2'+    filepath: '1.4.0.0'+    process: '1.2.3.0'+    array: '0.5.1.0'+    integer-gmp: '1.0.0.0'+    bin-package-db: '0.0.0.0'+    containers: '0.5.6.2'+    binary: '0.7.5.0'+    ghc-prim: '0.4.0.0'+    transformers: '0.4.2.0'+    deepseq: '1.4.1.1'+    pretty: '1.1.2.0'+    template-haskell: '2.10.0.0'+    directory: '1.2.2.0'+  ghc-version: '7.10.3'+  os: linux+  core-executables:+  - ghc+  - ghc-7.10.3+  - ghc-pkg+  - ghc-pkg-7.10.3+  - ghci+  - ghci-7.10.3+  - haddock+  - haddock-ghc-7.10.3+  - hp2ps+  - hpc+  - hsc2hs+  - runghc+  - runghc-7.10.3+  - runhaskell+  arch: x86_64+packages:+  drawille:+    users: []+    constraints:+      library-profiling: true+      flags: {}+      build-benchmarks: true+      skip-build: false+      tests: expect-success+      haddocks: expect-success+      maintainer: Pedro Tacla Yamada <tacla.yamada@gmail.com> @yamadapc+      version-range: ! '>=0.1.0.6 && <0.2'+    version: '0.1.0.6'+    github-pings:+    - yamadapc+    description:+      modules:+      - System.Drawille+      provided-exes:+      - image2term+      - senoid+      packages:+        base:+          components:+          - library+          - test-suite+          range: ==4.*+        hspec:+          components:+          - test-suite+          range: ! '>=1.11 && <2.3'+        containers:+          components:+          - library+          - test-suite+          range: ==0.5.*+        QuickCheck:+          components:+          - test-suite+          range: ! '>=2.6 && <3'+      tools: {}+tools:+- name: alex+  version: '3.1.7'+- name: c2hs+  version: '0.27.1'+- name: cpphs+  version: '1.19.3'+- name: happy+  version: '1.19.5'+- name: hsx2hs+  version: '0.13.4'+- name: gtk2hs-buildtools+  version: '0.13.0.5'
+ test/data/lts-2.22_conpact.yaml view
@@ -0,0 +1,497 @@+github-users:+  yesodweb:+  - snoyberg+  silkapp:+  - bergmark+  - hesselink+  elm-lang:+  - JoeyEremondi+  snapframework:+  - mightybyte+  haskell-ro:+  - mihaimaruseac+  faylang:+  - bergmark+  fpco:+  - snoyberg+  diagrams:+  - bergey+  - byorgey+  - fryguybob+  - jeffreyrosenbluth+system-info:+  core-packages:+    ghc: '7.8.4'+    hoopl: '3.10.0.1'+    bytestring: '0.10.4.0'+    unix: '2.7.0.1'+    haskeline: '0.7.1.2'+    Cabal: '1.18.1.5'+    base: '4.7.0.2'+    time: '1.4.2'+    xhtml: '3000.2.1'+    haskell98: '2.0.0.3'+    hpc: '0.6.0.1'+    filepath: '1.3.0.2'+    process: '1.2.0.0'+    array: '0.5.0.0'+    integer-gmp: '0.5.1.0'+    bin-package-db: '0.0.0.0'+    containers: '0.5.5.1'+    haskell2010: '1.1.2.0'+    binary: '0.7.1.0'+    ghc-prim: '0.3.1.0'+    old-time: '1.1.0.2'+    old-locale: '1.0.0.6'+    rts: '1.0'+    terminfo: '0.4.0.0'+    transformers: '0.3.0.0'+    deepseq: '1.3.0.2'+    pretty: '1.1.1.1'+    template-haskell: '2.9.0.0'+    directory: '1.2.1.0'+  ghc-version: '7.8.4'+  os: linux+  core-executables:+  - ghc+  - ghc-7.8.4+  - ghc-pkg+  - ghc-pkg-7.8.4+  - ghci+  - ghci-7.8.4+  - haddock+  - haddock-ghc-7.8.4+  - hp2ps+  - hpc+  - hsc2hs+  - runghc+  - runghc-7.8.4+  - runhaskell+  arch: x86_64+packages:+  conduit:+    users:+    - BlastHTTP+    - MFlow+    - MusicBrainz+    - amazonka+    - amazonka-core+    - authenticate+    - aws+    - binary-conduit+    - bloodhound+    - bzlib-conduit+    - cabal-src+    - cereal-conduit+    - classy-prelude-conduit+    - conduit+    - conduit-combinators+    - conduit-extra+    - cryptohash-conduit+    - csv-conduit+    - esqueleto+    - fb+    - gitlib+    - gitlib-libgit2+    - gitlib-test+    - hOpenPGP+    - hackage-mirror+    - hoogle+    - hopenpgp-tools+    - html-conduit+    - http-conduit+    - http-reverse-proxy+    - imagesize-conduit+    - keter+    - lzma-conduit+    - markdown+    - mime-mail-ses+    - monad-logger+    - network-conduit+    - network-conduit-tls+    - osdkeys+    - pagerduty+    - persistent+    - persistent-mongoDB+    - persistent-mysql+    - persistent-postgresql+    - persistent-sqlite+    - project-template+    - shell-conduit+    - simple-sendfile+    - soap+    - stackage-cli+    - stackage-curator+    - stm-conduit+    - tagstream-conduit+    - wai-conduit+    - wai-middleware-consul+    - xml-conduit+    - yackage+    - yaml+    - yesod-auth+    - yesod-auth-fb+    - yesod-bin+    - yesod-core+    - yesod-eventsource+    - yesod-fb+    - yesod-persistent+    - yesod-sitemap+    - yesod-static+    - yesod-websockets+    constraints:+      library-profiling: true+      flags: {}+      build-benchmarks: true+      skip-build: false+      tests: expect-success+      haddocks: expect-success+      version-range: ! '>=1.2.5 && <1.3'+    version: '1.2.5'+    github-pings:+    - snoyberg+    description:+      modules:+      - Data.Conduit+      - Data.Conduit.Internal+      - Data.Conduit.Internal.Fusion+      - Data.Conduit.Internal.List.Stream+      - Data.Conduit.Lift+      - Data.Conduit.List+      provided-exes: []+      packages:+        exceptions:+          components:+          - library+          - test-suite+          range: ! '>=0.6'+        void:+          components:+          - library+          - test-suite+          range: ! '>=0.5.5'+        mwc-random:+          components:+          - benchmark+          range: -any+        base:+          components:+          - library+          - test-suite+          - benchmark+          range: ! '>=4.3 && <5'+        hspec:+          components:+          - test-suite+          - benchmark+          range: ! '>=1.3'+        kan-extensions:+          components:+          - benchmark+          range: -any+        criterion:+          components:+          - benchmark+          range: -any+        lifted-base:+          components:+          - library+          range: ! '>=0.1'+        conduit:+          components:+          - test-suite+          - benchmark+          range: -any+        containers:+          components:+          - test-suite+          - benchmark+          range: -any+        mtl:+          components:+          - library+          - test-suite+          range: -any+        mmorph:+          components:+          - library+          range: -any+        transformers-base:+          components:+          - library+          range: ! '>=0.4.1 && <0.5'+        transformers:+          components:+          - library+          - test-suite+          - benchmark+          range: ! '>=0.2.2 && <0.5'+        deepseq:+          components:+          - benchmark+          range: -any+        QuickCheck:+          components:+          - test-suite+          range: ! '>=2.5'+        resourcet:+          components:+          - library+          - test-suite+          range: ==1.1.*+        safe:+          components:+          - test-suite+          range: -any+        vector:+          components:+          - benchmark+          range: -any+      tools: {}+  aeson:+    users:+    - HTF+    - MusicBrainz+    - Spock+    - aeson+    - aeson-pretty+    - aeson-qq+    - aeson-utils+    - amazonka-core+    - arbtt+    - authenticate+    - aws+    - bake+    - blank-canvas+    - bloodhound+    - classy-prelude-yesod+    - consul-haskell+    - criterion+    - descriptive+    - ede+    - fay+    - fb+    - generic-aeson+    - gipeda+    - gitson+    - groundhog+    - groundhog-th+    - hOpenPGP+    - haskell-names+    - haskell-packages+    - hasql-postgres+    - hdocs+    - heist+    - hoauth2+    - holy-project+    - hoogle+    - hopenpgp-tools+    - hpc-coveralls+    - hsdev+    - hspec-wai-json+    - ide-backend+    - ide-backend-common+    - jmacro+    - jmacro-rpc+    - jmacro-rpc-happstack+    - jmacro-rpc-snap+    - jose-jwt+    - json-autotype+    - json-schema+    - kansas-comet+    - keter+    - koofr-client+    - lens-aeson+    - mandrill+    - monad-logger-json+    - pagerduty+    - pandoc+    - pandoc-citeproc+    - pandoc-types+    - persistent+    - persistent-mongoDB+    - persistent-mysql+    - persistent-postgresql+    - persistent-sqlite+    - persistent-template+    - pipes-aeson+    - postgresql-simple+    - present+    - quandl-api+    - rest-core+    - rest-gen+    - rest-stringmap+    - rest-types+    - rethinkdb-client-driver+    - scotty+    - servant-client+    - servant-docs+    - servant-jquery+    - servant-server+    - shakespeare+    - snap+    - snaplet-fay+    - sourcemap+    - stackage-build-plan+    - stackage-curator+    - stackage-install+    - stackage-types+    - stackage-upload+    - statistics+    - stylish-haskell+    - thyme+    - tttool+    - users+    - users-postgresql-simple+    - users-test+    - waitra+    - webdriver+    - wreq+    - xml-to-json+    - yaml+    - yesod+    - yesod-auth+    - yesod-auth-deskcom+    - yesod-auth-fb+    - yesod-auth-oauth2+    - yesod-core+    - yesod-fay+    - yesod-fb+    - yesod-form+    - yesod-text-markdown+    constraints:+      library-profiling: true+      flags:+        old-locale: true+      build-benchmarks: true+      skip-build: false+      tests: expect-success+      haddocks: expect-success+      version-range: ! '>=0.8.0.2 && <0.8.1'+    version: '0.8.0.2'+    github-pings:+    - bos+    description:+      modules:+      - Data.Aeson+      - Data.Aeson.Encode+      - Data.Aeson.Generic+      - Data.Aeson.Parser+      - Data.Aeson.TH+      - Data.Aeson.Types+      provided-exes: []+      packages:+        test-framework-hunit:+          components:+          - test-suite+          range: -any+        bytestring:+          components:+          - library+          - test-suite+          range: ! '>=0.10.4.0'+        test-framework:+          components:+          - test-suite+          range: -any+        base:+          components:+          - library+          - test-suite+          range: ==4.*+        time:+          components:+          - library+          - test-suite+          range: <1.5+        unordered-containers:+          components:+          - library+          - test-suite+          range: ! '>=0.2.3.0'+        text:+          components:+          - library+          - test-suite+          range: ! '>=1.1.1.0'+        syb:+          components:+          - library+          range: -any+        test-framework-quickcheck2:+          components:+          - test-suite+          range: -any+        dlist:+          components:+          - library+          range: ! '>=0.2'+        HUnit:+          components:+          - test-suite+          range: -any+        containers:+          components:+          - library+          - test-suite+          range: -any+        ghc-prim:+          components:+          - library+          - test-suite+          range: ! '>=0.2'+        old-locale:+          components:+          - library+          range: -any+        mtl:+          components:+          - library+          range: -any+        hashable:+          components:+          - library+          range: ! '>=1.1.2.0'+        attoparsec:+          components:+          - library+          - test-suite+          range: ! '>=0.11.3.4'+        deepseq:+          components:+          - library+          range: -any+        scientific:+          components:+          - library+          range: ! '>=0.3.1 && <0.4'+        QuickCheck:+          components:+          - test-suite+          range: -any+        aeson:+          components:+          - test-suite+          range: -any+        template-haskell:+          components:+          - library+          - test-suite+          range: ! '>=2.4'+        vector:+          components:+          - library+          - test-suite+          range: ! '>=0.7.1'+      tools: {}+tools:+- name: alex+  version: '3.1.4'+- name: c2hs+  version: '0.25.2'+- name: cpphs+  version: '1.19.2'+- name: happy+  version: '1.19.5'+- name: gtk2hs-buildtools+  version: '0.13.0.4'
+ test/data/lts-4.2.yaml view

file too large to diff

+ test/data/lts-7.0_conpact.yaml view
@@ -0,0 +1,676 @@+all-cabal-hashes-commit: 5d00e91223715777b5551a98a2a0863e72c7fc0f+github-users:+  yesodweb:+  - snoyberg+  telegram-api:+  - klappvisor+  stackbuilders:+  - jpvillaisaza+  - jsantos17+  - jsl+  - mrkkrp+  - sestrella+  silkapp:+  - bergmark+  - hesselink+  Happstack:+  - stepcut+system-info:+  core-packages:+    ghc: '8.0.1'+    hoopl: '3.10.2.1'+    bytestring: '0.10.8.1'+    unix: '2.7.2.0'+    base: '4.9.0.0'+    time: '1.6.0.1'+    hpc: '0.6.0.3'+    filepath: '1.4.1.0'+    process: '1.4.2.0'+    array: '0.5.1.1'+    integer-gmp: '1.0.0.1'+    containers: '0.5.7.1'+    ghc-boot: '8.0.1'+    binary: '0.8.3.0'+    ghc-prim: '0.5.0.0'+    ghci: '8.0.1'+    rts: '1.0'+    transformers: '0.5.2.0'+    deepseq: '1.4.2.0'+    ghc-boot-th: '8.0.1'+    pretty: '1.1.3.3'+    template-haskell: '2.11.0.0'+    directory: '1.2.6.2'+  ghc-version: '8.0.1'+  os: linux+  core-executables:+  - ghc+  - ghc-8.0.1+  - ghc-pkg+  - ghc-pkg-8.0.1+  - ghci+  - ghci-8.0.1+  - haddock+  - haddock-ghc-8.0.1+  - hp2ps+  - hpc+  - hsc2hs+  - runghc+  - runghc-8.0.1+  - runhaskell+  arch: x86_64+packages:+  conduit:+    users:+    - BlastHTTP+    - HTTP+    - MFlow+    - MusicBrainz+    - amazonka+    - amazonka-core+    - amazonka-test+    - atndapi+    - atom-conduit+    - authenticate+    - aws+    - b9+    - binary-conduit+    - bitcoin-api-extra+    - bzlib-conduit+    - cabal-src+    - cassava-conduit+    - cereal-conduit+    - classy-prelude-conduit+    - conduit+    - conduit-combinators+    - conduit-extra+    - conduit-iconv+    - conduit-parse+    - cryptohash-conduit+    - cryptonite-conduit+    - dns+    - editor-open+    - fb+    - fold-debounce-conduit+    - fsnotify-conduit+    - gitlib+    - gitlib-libgit2+    - gitlib-test+    - gogol+    - gogol-core+    - hOpenPGP+    - hackage-mirror+    - haskell-spacegoo+    - haskoin-core+    - hoogle+    - hopenpgp-tools+    - html-conduit+    - http-conduit+    - http-reverse-proxy+    - hw-conduit+    - hw-rankselect+    - hw-succinct+    - imagesize-conduit+    - imm+    - irc-client+    - irc-conduit+    - keter+    - machines+    - markdown+    - mime-mail-ses+    - monad-logger+    - ndjson-conduit+    - network-conduit-tls+    - opml-conduit+    - osdkeys+    - pager+    - pagerduty+    - persistent+    - persistent-postgresql+    - persistent-sqlite+    - project-template+    - rss-conduit+    - sandi+    - serf+    - shell-conduit+    - simple-sendfile+    - soap+    - stack+    - stackage-curator+    - stm-conduit+    - store+    - tagstream-conduit+    - thumbnail-plus+    - twitter-conduit+    - wai-conduit+    - wai-middleware-consul+    - withdependencies+    - xlsior+    - xlsx+    - xml-conduit+    - xml-conduit-parse+    - yackage+    - yaml+    - yesod-auth+    - yesod-bin+    - yesod-core+    - yesod-eventsource+    - yesod-fb+    - yesod-persistent+    - yesod-sitemap+    - yesod-static+    - yesod-websockets+    - zip+    constraints:+      benches: expect-success+      library-profiling: true+      flags: {}+      build-benchmarks: true+      skip-build: false+      tests: expect-success+      haddocks: expect-success+      configure-args: []+      version-range: -any+    version: '1.2.7'+    cabal-file-info:+      size: 4041+      hashes:+        MD5: 3cac157771a3fe620548760f44a27285+        Skein512_512: 70ecee198d5e0281de4163b8ec8f9e06231dd82d1fe8163a0632ea91ed7c0e35313f622cfc4cb250b05fd893d89901b67a7ec4e4fb3c019b6f25a7d23ecc3018+        SHA1: 147aae20b2b1a425833ddf7825580475105b86eb+        SHA512: 888471c06ba9db0a84d7212af48461f33277fa61668391a61cd7c2e8cda95d768c10b7cf8c9f1570249859a05e4eb8c6ab9125ecda37cb3963f63651844fd530+        SHA256: f5e83ea27ee3cc4a6c190336143d38a468c228f53342a49c63d1fac18e4079c7+        GitSHA1: 7750ddac3f1edf2499d37dbbcbcfac37db6a89db+    github-pings:+    - snoyberg+    description:+      cabal-version: '1.8'+      modules:+      - Data.Conduit+      - Data.Conduit.Internal+      - Data.Conduit.Internal.Fusion+      - Data.Conduit.Internal.List.Stream+      - Data.Conduit.Lift+      - Data.Conduit.List+      provided-exes: []+      packages:+        exceptions:+          components:+          - library+          - test-suite+          range: ! '>=0.6'+        mwc-random:+          components:+          - benchmark+          range: -any+        base:+          components:+          - library+          - test-suite+          - benchmark+          range: ! '>=4.5 && <5'+        hspec:+          components:+          - test-suite+          - benchmark+          range: ! '>=1.3'+        kan-extensions:+          components:+          - benchmark+          range: -any+        criterion:+          components:+          - benchmark+          range: -any+        lifted-base:+          components:+          - library+          range: ! '>=0.1'+        conduit:+          components:+          - test-suite+          - benchmark+          range: -any+        containers:+          components:+          - test-suite+          - benchmark+          range: -any+        mtl:+          components:+          - library+          - test-suite+          range: -any+        mmorph:+          components:+          - library+          range: -any+        transformers-base:+          components:+          - library+          range: ! '>=0.4.1 && <0.5'+        transformers:+          components:+          - library+          - test-suite+          - benchmark+          range: ! '>=0.2.2'+        deepseq:+          components:+          - benchmark+          range: -any+        QuickCheck:+          components:+          - test-suite+          range: ! '>=2.7'+        resourcet:+          components:+          - library+          - test-suite+          range: ==1.1.*+        safe:+          components:+          - test-suite+          range: -any+        vector:+          components:+          - benchmark+          range: -any+      tools: {}+  aeson:+    users:+    - HTF+    - MusicBrainz+    - Spock-api+    - Spock-core+    - aeson+    - aeson-better-errors+    - aeson-casing+    - aeson-compat+    - aeson-injector+    - aeson-pretty+    - aeson-qq+    - aeson-utils+    - amazonka-core+    - amazonka-test+    - api-field-json-th+    - arbtt+    - atndapi+    - authenticate+    - aws+    - b9+    - bake+    - base32string+    - base58string+    - bimap-server+    - binary-orphans+    - binary-tagged+    - bitcoin-api+    - bitcoin-payment-channel+    - bitx-bitcoin+    - blank-canvas+    - bloodhound+    - bower-json+    - cabal2nix+    - cacophony+    - cayley-client+    - cheapskate+    - clash-lib+    - classy-prelude-yesod+    - clckwrks+    - clckwrks-plugin-page+    - configuration-tools+    - consul-haskell+    - criterion+    - descriptive+    - distribution-nixpkgs+    - docopt+    - doctest-discover+    - ede+    - ekg+    - ekg-json+    - elm-bridge+    - emailaddress+    - envelope+    - etcd+    - eventstore+    - fast-builder+    - fay+    - fb+    - find-clumpiness+    - forecast-io+    - generic-aeson+    - gipeda+    - giphy-api+    - github-types+    - github-webhook-handler+    - gitson+    - glabrous+    - gogol+    - gogol-core+    - google-cloud+    - graylog+    - hOpenPGP+    - hailgun+    - handwriting+    - happstack-authenticate+    - haskell-names+    - haskell-neo4j-client+    - haskell-packages+    - haskell-spacegoo+    - haskoin-core+    - hasql+    - hexstring+    - hjsonpointer+    - hjsonschema+    - hoauth2+    - holy-project+    - hoogle+    - hopenpgp-tools+    - hpack+    - hpack-convert+    - hpc-coveralls+    - hruby+    - hsebaysdk+    - hspec-expectations-pretty-diff+    - hspec-golden-aeson+    - hspec-wai-json+    - hspec-webdriver+    - htoml+    - http-conduit+    - http-streams+    - http2+    - hworker+    - hworker-ses+    - ical+    - idris+    - imm+    - inline-r+    - insert-ordered-containers+    - jmacro+    - jmacro-rpc+    - jmacro-rpc-happstack+    - jose+    - jose-jwt+    - json-autotype+    - json-rpc-generic+    - json-schema+    - jwt+    - kansas-comet+    - kawhi+    - keter+    - koofr-client+    - kraken+    - language-puppet+    - lens-aeson+    - mandrill+    - microformats2-parser+    - microlens-aeson+    - moesocks+    - monad-logger-json+    - mustache+    - ndjson-conduit+    - octane+    - omnifmt+    - opaleye+    - opensource+    - pagerduty+    - pandoc+    - pandoc-citeproc+    - pandoc-types+    - path+    - persistent+    - persistent-postgresql+    - persistent-redis+    - persistent-sqlite+    - persistent-template+    - pinboard+    - pipes-aeson+    - postgresql-binary+    - postgresql-query+    - postgresql-simple+    - profiteur+    - purescript+    - quantum-random+    - ratel+    - rest-core+    - rest-gen+    - rest-stringmap+    - rest-types+    - rethinkdb+    - rethinkdb-client-driver+    - scotty+    - servant+    - servant-aeson-specs+    - servant-client+    - servant-docs+    - servant-js+    - servant-mock+    - servant-purescript+    - servant-server+    - servant-subscriber+    - servant-swagger+    - servant-swagger-ui+    - servant-yaml+    - serversession+    - shakespeare+    - simple+    - simple-templates+    - slug+    - smoothie+    - smsaero+    - solga+    - sourcemap+    - stache+    - stack+    - stackage-curator+    - stackage-types+    - statistics+    - stratosphere+    - strict-base-types+    - stripe-core+    - strive+    - stylish-haskell+    - swagger+    - swagger2+    - text-region+    - these+    - thyme+    - tttool+    - twitter-conduit+    - twitter-feed+    - twitter-types+    - ua-parser+    - userid+    - users+    - wai-extra+    - wai-middleware-content-type+    - waitra+    - webdriver+    - webdriver-angular+    - werewolf+    - werewolf-slack+    - wreq+    - xlsx-tabular+    - yahoo-finance-api+    - yaml+    - yesod+    - yesod-auth+    - yesod-auth-oauth2+    - yesod-core+    - yesod-fay+    - yesod-fb+    - yesod-form+    - yesod-gitrev+    - yesod-job-queue+    - yesod-static-angular+    constraints:+      benches: expect-success+      library-profiling: true+      flags: {}+      build-benchmarks: true+      skip-build: false+      tests: expect-success+      haddocks: expect-success+      maintainer: Adam Bergmark <adam@bergmark.nl> @bergmark+      configure-args: []+      version-range: <1.0+    version: '0.11.2.1'+    cabal-file-info:+      size: 4634+      hashes:+        MD5: b2b4ef66114e351b788af8df16513df9+        Skein512_512: 2c1a12cacd8bb458c11d2b94125f3fcdc976f81daf2cf7f6d4795a734ea0accbbc950916be70703cd088be646032c1aef3108f3b220baf8c931efd4e6a1dec2d+        SHA1: 92b374f030103c92dbf9ce22240dde0109e28209+        SHA512: 33bc7d601f800354ce5b8087122b4d9cc40d1d62623f5a89e355bf04ea4a2d92688ff3941cb0d8586179bdd01c902e99eb504ca66681540f21cdab1fc00e54d7+        SHA256: 9d08400d818255b7ee068ed6cfe2d4db1270066e4699f8c85afa6efc63787821+        GitSHA1: 06f8123070664e3d80d39baf5e3e8c1f92c3003c+    github-pings:+    - bos+    description:+      cabal-version: '1.10'+      modules:+      - Data.Aeson+      - Data.Aeson.Encode+      - Data.Aeson.Internal+      - Data.Aeson.Internal.Time+      - Data.Aeson.Parser+      - Data.Aeson.TH+      - Data.Aeson.Types+      provided-exes: []+      packages:+        test-framework-hunit:+          components:+          - test-suite+          range: -any+        bytestring:+          components:+          - library+          - test-suite+          range: ! '>=0.10.4.0'+        test-framework:+          components:+          - test-suite+          range: -any+        fail:+          components:+          - library+          range: ==4.9.*+        base:+          components:+          - library+          - test-suite+          range: ! '>=4.5 && <5'+        time:+          components:+          - library+          - test-suite+          range: ! '>=1.5'+        unordered-containers:+          components:+          - library+          - test-suite+          range: ! '>=0.2.5.0'+        text:+          components:+          - library+          - test-suite+          range: ! '>=1.1.1.0'+        syb:+          components:+          - library+          range: -any+        test-framework-quickcheck2:+          components:+          - test-suite+          range: -any+        dlist:+          components:+          - library+          range: ! '>=0.2'+        HUnit:+          components:+          - test-suite+          range: -any+        base-orphans:+          components:+          - test-suite+          range: ! '>=0.5.3 && <0.6'+        tagged:+          components:+          - library+          - test-suite+          range: ! '>=0.8.3 && <0.9'+        containers:+          components:+          - library+          - test-suite+          range: -any+        quickcheck-instances:+          components:+          - test-suite+          range: ! '>=0.3.12'+        ghc-prim:+          components:+          - library+          - test-suite+          range: ! '>=0.2'+        mtl:+          components:+          - library+          range: -any+        hashable:+          components:+          - library+          - test-suite+          range: ! '>=1.1.2.0'+        attoparsec:+          components:+          - library+          - test-suite+          range: ! '>=0.13.0.1'+        transformers:+          components:+          - library+          range: -any+        deepseq:+          components:+          - library+          range: -any+        scientific:+          components:+          - library+          range: ! '>=0.3.1 && <0.4'+        QuickCheck:+          components:+          - test-suite+          range: ! '>=2.7 && <2.10'+        aeson:+          components:+          - test-suite+          range: -any+        template-haskell:+          components:+          - library+          - test-suite+          range: ! '>=2.7'+        vector:+          components:+          - library+          - test-suite+          range: ! '>=0.8'+      tools: {}+tools:+- name: alex+  version: '3.1.7'+- name: c2hs+  version: '0.28.1'+- name: cabal-install+  version: '1.24.0.0'+- name: cpphs+  version: '1.20.2'+- name: happy+  version: '1.19.5'+- name: hsx2hs+  version: '0.13.5'+- name: gtk2hs-buildtools+  version: '0.13.2.1'