on master help sign in
Start of Stackage2: CorePackages
commit97949eb86ce71eb2c0adef7091c1cc63fa124bac authorMichael Snoyman <michael@snoyman.com> dateThu 4 Dec 2014, 13:17 (12 years ago) parent514a920
5 files changed+140
Stackage2/CorePackages.hs+32 Stackage2/Prelude.hs+73 stackage.cabal+20 test/Spec.hs+1 test/Stackage2/CorePackagesSpec.hs+14
Stackage2/CorePackages.hsnew file+32
@@ -0,0 +1,32 @@
1+{-# LANGUAGE NoImplicitPrelude, OverloadedStrings #-}
2+module Stackage2.CorePackages
3+ ( getCorePackages
4+ ) where
5+
6+import Stackage2.Prelude
7+import qualified Data.Text as T
8+
9+-- | Get a @Map@ of all of the core packages. Core packages are defined as
10+-- packages which ship with GHC itself.
11+--
12+-- Precondition: GHC global package database has only core packages, and GHC
13+-- ships with just a single version of each packages.
14+getCorePackages :: IO (Map PackageName Version)
15+getCorePackages =
16+ withCheckedProcess cp $ \ClosedStream src Inherited ->
17+ src $$ decodeUtf8C =$ linesUnboundedC =$ foldMapMC parsePackage
18+ where
19+ cp = proc "ghc-pkg" ["--no-user-package-conf", "list"]
20+ parsePackage t
21+ | ":" `isInfixOf` t = return mempty
22+ | Just p <- stripSuffix "-" p' = singletonMap
23+ <$> simpleParse p
24+ <*> simpleParse v
25+ | otherwise = return mempty
26+ where
27+ (p', v) = T.breakOnEnd "-" $ dropParens $ T.strip t
28+
29+ dropParens s
30+ | length s > 2 && headEx s == '(' && lastEx s == ')' =
31+ initEx $ tailEx s
32+ | otherwise = s
Stackage2/Prelude.hsnew file+73
@@ -0,0 +1,73 @@
1+{-# LANGUAGE DeriveDataTypeable #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+{-# LANGUAGE TypeFamilies #-}
5+module Stackage2.Prelude
6+ ( module X
7+ , module Stackage2.Prelude
8+ ) where
9+
10+import ClassyPrelude.Conduit as X
11+import Data.Conduit.Process as X
12+import Data.Typeable (TypeRep, typeOf)
13+import Distribution.Package as X (PackageName (PackageName))
14+import qualified Distribution.Text as DT
15+import Distribution.Version as X (Version (..))
16+import System.Exit (ExitCode (ExitSuccess))
17+
18+unPackageName :: PackageName -> Text
19+unPackageName (PackageName str) = pack str
20+
21+mkPackageName :: Text -> PackageName
22+mkPackageName = PackageName . unpack
23+
24+display :: (IsString text, Element text ~ Char, DT.Text a) => a -> text
25+display = fromString . DT.display
26+
27+simpleParse :: (MonadThrow m, DT.Text a, Typeable a, MonoFoldable text, Element text ~ Char)
28+ => text -> m a
29+simpleParse orig = withTypeRep $ \rep ->
30+ case DT.simpleParse str of
31+ Nothing -> throwM (ParseFailed rep (pack str))
32+ Just v -> return v
33+ where
34+ str = unpack orig
35+
36+ withTypeRep :: Typeable a => (TypeRep -> m a) -> m a
37+ withTypeRep f =
38+ res
39+ where
40+ res = f (typeOf (unwrap res))
41+
42+ unwrap :: m a -> a
43+ unwrap _ = error "unwrap"
44+
45+data ParseFailed = ParseFailed TypeRep Text
46+ deriving (Show, Typeable)
47+instance Exception ParseFailed
48+
49+data ProcessExitedUnsuccessfully = ProcessExitedUnsuccessfully CreateProcess ExitCode
50+ deriving Typeable
51+instance Show ProcessExitedUnsuccessfully where
52+ show (ProcessExitedUnsuccessfully cp ec) = concat
53+ [ "Process exited with "
54+ , show ec
55+ , ": "
56+ , showCmdSpec (cmdspec cp)
57+ ]
58+ where
59+ showCmdSpec (ShellCommand str) = str
60+ showCmdSpec (RawCommand x xs) = unwords (x:xs)
61+instance Exception ProcessExitedUnsuccessfully
62+
63+checkExitCode :: MonadThrow m => CreateProcess -> ExitCode -> m ()
64+checkExitCode _ ExitSuccess = return ()
65+checkExitCode cp ec = throwM $ ProcessExitedUnsuccessfully cp ec
66+
67+-- FIXME move into streaming-commons?
68+withCheckedProcess cp f = do
69+ (x, y, z, sph) <- streamingProcess cp
70+ res <- f x y z
71+ ec <- waitForStreamingProcess sph
72+ checkExitCode cp ec
73+ return res
stackage.cabal+20
@@ -29,6 +29,9 @@ library
2929 Stackage.Select
3030 Stackage.GhcPkg
3131 Stackage.ServerFiles
32+
33+ Stackage2.Prelude
34+ Stackage2.CorePackages
3235 build-depends: base >= 4 && < 5
3336 , containers
3437 , Cabal >= 1.14
@@ -43,6 +46,10 @@ library
4346 , time
4447 , utf8-string
4548
49+ , conduit-extra
50+ , classy-prelude-conduit
51+ , text
52+
4653executable stackage
4754 hs-source-dirs: app
4855 main-is: stackage.hs
@@ -50,6 +57,19 @@ executable stackage
5057 , stackage
5158 , containers
5259
60+test-suite spec
61+ type: exitcode-stdio-1.0
62+ default-language: Haskell2010
63+ hs-source-dirs: test
64+ main-is: Spec.hs
65+ other-modules: Stackage2.CorePackagesSpec
66+ build-depends: base
67+ , stackage
68+ , hspec
69+ , QuickCheck
70+ , text
71+ , classy-prelude-conduit
72+
5373source-repository head
5474 type: git
5575 location: https://github.com/fpco/stackage
test/Spec.hsnew file+1
@@ -0,0 +1 @@
1+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
test/Stackage2/CorePackagesSpec.hsnew file+14
@@ -0,0 +1,14 @@
1+{-# LANGUAGE OverloadedStrings, NoImplicitPrelude #-}
2+module Stackage2.CorePackagesSpec (spec) where
3+
4+import Stackage2.CorePackages
5+import Stackage2.Prelude
6+import Test.Hspec
7+
8+spec :: Spec
9+spec = do
10+ it "works" $ void getCorePackages
11+ it "contains known core packages" $ do
12+ m <- getCorePackages
13+ forM_ (words "ghc containers base") $ \p ->
14+ m `shouldSatisfy` (member (PackageName p))