1module Stackage.LoadDatabase where
3import qualified Codec.Archive.Tar as Tar
4import qualified Codec.Archive.Tar.Entry as TarEntry
5import Control.Exception (throwIO)
6import Control.Monad (guard)
7import qualified Data.ByteString.Lazy as L
8import qualified Data.ByteString.Lazy.Char8 as L8
9import Data.List (stripPrefix)
10import qualified Data.Map as Map
11import Data.Monoid (Monoid (..))
12import Data.Set (member)
13import qualified Data.Set as Set
14import Distribution.Package (Dependency (Dependency))
15import Distribution.PackageDescription (condExecutables,
19import Distribution.PackageDescription.Parse (ParseResult (ParseOk),
20 parsePackageDescription)
21import Distribution.Text (simpleParse)
22import Distribution.Version (withinRange)
24import System.Directory (getAppUserDataDirectory)
25import System.FilePath ((</>))
27-- | Load the raw package database.
29-- We want to put in some restrictions:
31-- * Drop all core packages. We never want to install a new version of
32-- those, nor include them in the package list.
34-- * For packages with a specific version bound, find the maximum matching
37-- * For other packages, select the maximum version number.
38loadPackageDB :: Set PackageName -- ^ core packages
39 -> Map PackageName VersionRange -- ^ additional deps
41loadPackageDB core deps = do
42 c <- getAppUserDataDirectory "cabal"
43 let tarName = c </> "packages" </> "hackage.haskell.org" </> "00-index.tar"
44 lbs <- L.readFile tarName
45 addEntries mempty $ Tar.read lbs
47 addEntries :: PackageDB -> Tar.Entries Tar.FormatError -> IO PackageDB
48 addEntries _ (Tar.Fail e) = throwIO e
49 addEntries db Tar.Done = return db
50 addEntries db (Tar.Next e es) = addEntry db e >>= flip addEntries es
52 addEntry :: PackageDB -> Tar.Entry -> IO PackageDB
54 case getPackageVersion $ TarEntry.fromTarPathToPosixPath (TarEntry.entryTarPath e) of
57 | p `member` core -> return pdb
59 case Map.lookup p deps of
61 | not $ withinRange v vrange -> return pdb
63 case Tar.entryContent e of
64 Tar.NormalFile bs _ -> return $ mappend pdb $ PackageDB $ Map.singleton p PackageInfo
66 , piDeps = parseDeps bs
71 case parsePackageDescription $ L8.unpack lbs of
72 ParseOk _ gpd -> mconcat
73 [ maybe mempty go $ condLibrary gpd
74 , mconcat $ map (go . snd) $ condExecutables gpd
75 , mconcat $ map (go . snd) $ condTestSuites gpd
76 -- , mconcat $ map (go . snd) $ condBenchmarks gpd
80 go = Set.fromList . map (\(Dependency p _) -> p) . condTreeConstraints
82 getPackageVersion :: FilePath -> Maybe (PackageName, Version)
83 getPackageVersion fp = do
84 let (package', s1) = break (== '/') fp
85 package = PackageName package'
86 s2 <- stripPrefix "/" s1
87 let (version', s3) = break (== '/') s2
88 version <- simpleParse version'
89 s4 <- stripPrefix "/" s3
90 guard $ s4 == package' ++ ".cabal"
91 Just (package, version)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list