git.iko.soy/typeable/cabal2nix
on v2.0 help sign in
79 lines 2.9 kB history raw
1{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE TemplateHaskell #-}
4module HackageGit where
6import Control.Monad
7import Control.Lens hiding ( (<.>) )
8import Data.Aeson
9import Data.ByteString.Char8 ( ByteString )
10import qualified Data.ByteString.Char8 as BS
11import Data.ByteString.Lazy.Char8 ( fromStrict )
12import Data.Digest.Pure.SHA ( sha256, showDigest )
13import Data.Map as Map
14import Data.Set as Set
15import Data.String
16import Data.String.UTF8 ( toString, fromRep )
17import Distribution.Nixpkgs.Haskell.OrphanInstances ( )
18import Distribution.Package
19import Distribution.PackageDescription
20import Distribution.PackageDescription.Parse ( parsePackageDescription, ParseResult(..) )
21import Distribution.Text
22import Distribution.Version
23import System.Directory
24import System.FilePath
26type Hackage = Map PackageName (Set Version)
28readHackage :: FilePath -> IO Hackage
29readHackage path = getSubDirs path >>= foldM discoverPackageVersions mempty
30 where
31 discoverPackageVersions :: Hackage -> String -> IO Hackage
32 discoverPackageVersions db pkg = do
33 vs <- getSubDirs (path </> pkg)
34 return (Map.insert (PackageName pkg) (Set.fromList (Prelude.map fromString vs)) db)
36getSubDirs :: FilePath -> IO [FilePath]
37getSubDirs path = do
38 let isDirectory p = doesDirectoryExist (path </> p)
39 getDirectoryContents path >>= filterM isDirectory . Prelude.filter (\x -> head x /= '.')
41decodeUTF8 :: ByteString -> String
42decodeUTF8 = toString . fromRep
44type SHA256Hash = String
46readPackage :: FilePath -> PackageIdentifier -> IO (GenericPackageDescription, SHA256Hash)
47readPackage dirPrefix (PackageIdentifier name version) = do
48 let cabalFile = dirPrefix </> unPackageName name </> display version </> unPackageName name <.> "cabal"
49 buf <- BS.readFile cabalFile
50 cabal <- case parsePackageDescription (decodeUTF8 buf) of
51 ParseOk _ a -> return a
52 ParseFailed err -> fail (cabalFile ++ ": " ++ show err)
53 return (cabal, mkSHA256 buf)
55mkSHA256 :: ByteString -> SHA256Hash
56mkSHA256 = showDigest . sha256 . fromStrict
58declareLenses [d|
59 data Meta = Meta { hashes :: Map String String
60 , locations :: [String]
61 , pkgsize :: Int
62 }
63 deriving (Show)
64 |]
66instance FromJSON Meta where
67 parseJSON (Object v) = Meta
68 <$> v .: "package-hashes"
69 <*> v .: "package-locations"
70 <*> v .: "package-size"
71 parseJSON o = fail ("invalid Cabal metadata: " ++ show o)
73readPackageMeta :: FilePath -> PackageIdentifier -> IO Meta
74readPackageMeta dirPrefix (PackageIdentifier name version) = do
75 let metaFile = dirPrefix </> unPackageName name </> display version </> unPackageName name <.> "json"
76 buf <- BS.readFile metaFile
77 case eitherDecodeStrict buf of
78 Left msg -> fail (metaFile ++ ": " ++ msg)
79 Right x -> return x