@@ -7,6 +7,8 @@
7-- | Dealing with the 00-index file and all its cabal files.
7-- | Dealing with the 00-index file and all its cabal files.
8module Stackage2.PackageIndex
8module Stackage2.PackageIndex
9 ( sourcePackageIndex
9 ( sourcePackageIndex
10+ , UnparsedCabalFile (..)
11+ , getLatestDescriptions
12import qualified Codec.Archive.Tar as Tar
14import qualified Codec.Archive.Tar as Tar
@@ -14,7 +16,7 @@ import qualified Codec.Archive.Tar.Entry as TarEntry
14import Data.Conduit.Lazy (MonadActive,
16import Data.Conduit.Lazy (MonadActive,
15 lazyConsume)
17 lazyConsume)
16import qualified Data.Text as T
18import qualified Data.Text as T
17−import Distribution.PackageDescription (GenericPackageDescription)
19+import Distribution.PackageDescription (GenericPackageDescription, packageDescription, package)
18import Distribution.PackageDescription.Parse (ParseResult (..),
20import Distribution.PackageDescription.Parse (ParseResult (..),
19 parsePackageDescription)
21 parsePackageDescription)
20import Distribution.ParseUtils (PError)
22import Distribution.ParseUtils (PError)
@@ -42,12 +44,16 @@ getPackageIndexPath = liftIO $ do
42 ("remote-repo-cache", stripPrefix ":" -> Just v) <- Just $ break (== ':') s
44 ("remote-repo-cache", stripPrefix ":" -> Just v) <- Just $ break (== ':') s
43 Just $ fpFromText $ T.strip v
45 Just $ fpFromText $ T.strip v
47+-- | A cabal file with name and version parsed from the filepath, and the
48+-- package description itself ready to be parsed. It's left in unparsed form
45data UnparsedCabalFile = UnparsedCabalFile
50data UnparsedCabalFile = UnparsedCabalFile
46 { ucfName :: PackageName
51 { ucfName :: PackageName
47 , ucfVersion :: Version
52 , ucfVersion :: Version
48 , ucfParse :: forall m. MonadThrow m => m GenericPackageDescription
53 , ucfParse :: forall m. MonadThrow m => m GenericPackageDescription
56+-- | Stream all of the cabal files from the 00-index tar file.
51sourcePackageIndex :: (MonadThrow m, MonadResource m, MonadActive m, MonadBaseControl IO m)
57sourcePackageIndex :: (MonadThrow m, MonadResource m, MonadActive m, MonadBaseControl IO m)
52 => Producer m UnparsedCabalFile
58 => Producer m UnparsedCabalFile
53sourcePackageIndex = do
59sourcePackageIndex = do
@@ -68,14 +74,20 @@ sourcePackageIndex = do
68 yield UnparsedCabalFile
74 yield UnparsedCabalFile
69 { ucfName = name
75 { ucfName = name
70 , ucfVersion = version
76 , ucfVersion = version
71− , ucfParse = goContent (Tar.entryPath e) lbs
77+ , ucfParse = goContent (Tar.entryPath e) name version lbs
73 | otherwise = return ()
79 | otherwise = return ()
75− goContent fp lbs =
81+ goContent fp name version lbs =
76 case parsePackageDescription $ unpack $ decodeUtf8 lbs of
82 case parsePackageDescription $ unpack $ decodeUtf8 lbs of
77 ParseFailed e -> throwM $ CabalParseException (fpFromString fp) e
83 ParseFailed e -> throwM $ CabalParseException (fpFromString fp) e
78− ParseOk _warnings gpd -> return gpd
84+ ParseOk _warnings gpd -> do
85+ let pd = packageDescription gpd
86+ PackageIdentifier name' version' = package pd
87+ when (name /= name' || version /= version') $
88+ throwM $ MismatchedNameVersion (fpFromString fp)
89+ name name' version version'
80 parseNameVersion t1 = do
92 parseNameVersion t1 = do
81 let (p', t2) = break (== '/') t1
93 let (p', t2) = break (== '/') t1
@@ -92,5 +104,25 @@ data InvalidCabalPath = InvalidCabalPath Text Text
92instance Exception InvalidCabalPath
104instance Exception InvalidCabalPath
94data CabalParseException = CabalParseException FilePath PError
106data CabalParseException = CabalParseException FilePath PError
107+ | MismatchedNameVersion FilePath PackageName PackageName Version Version
95 deriving (Show, Typeable)
108 deriving (Show, Typeable)
96instance Exception CabalParseException
109instance Exception CabalParseException
111+-- | Get all of the latest descriptions for name/version pairs matching the
113+getLatestDescriptions :: MonadIO m
114+ => (PackageName -> Version -> Bool)
115+ -> m (Map PackageName (Version, GenericPackageDescription))
116+getLatestDescriptions f = liftIO $ do
117+ m <- runResourceT $ sourcePackageIndex $$ filterC f' =$ foldlC add mempty
120+ return (ucfVersion ucf, gpd)
122+ f' ucf = f (ucfName ucf) (ucfVersion ucf)
124+ case lookup name m of
125+ Just ucf' | ucfVersion ucf < ucfVersion ucf' -> m
126+ _ -> insertMap name ucf m