@@ -1,39 +1,53 @@
1−-- Run: cabal build -j hackage2nix && dist/build/hackage2nix/hackage2nix >hackage-packages.nix
1+-- Run: cabal build -j hackage2nix && dist/build/hackage2nix/hackage2nix >~/.nix-defexpr/pkgs/development/haskell-modules/hackage-packages.nix
22
33module Main ( main ) where
44
55import Cabal2Nix.Generate
6−import Cabal2Nix.Name
6+-- import Cabal2Nix.Name
77import Cabal2Nix.Package
88import Control.Monad
99import Control.Monad.Par.Combinator
1010import Control.Monad.Par.IO
1111import Control.Monad.Trans
12−import Control.Monad.Trans.Maybe
12+import Data.ByteString.Lazy ( ByteString )
13+import Data.Digest.Pure.SHA ( sha256, showDigest )
1314import Data.Map ( Map )
1415import qualified Data.Map as Map
1516import Data.Monoid
1617import Data.Set ( Set )
1718import qualified Data.Set as Set
18−import Distribution.Hackage.DB ( Hackage, readHackage, GenericPackageDescription )
19+import Distribution.Hackage.DB ( Hackage )
20+import qualified Distribution.Hackage.DB.Parsed as Unparsed ( parsePackage )
21+import qualified Distribution.Hackage.DB.Unparsed as Unparsed
1922import Distribution.NixOS.Derivation.Cabal
20−import Distribution.NixOS.Derivation.Meta
21−import Distribution.NixOS.Fetch
2223import Distribution.NixOS.PrettyPrinting hiding ( (<>) )
2324import Distribution.PackageDescription hiding ( buildDepends, extraLibs, buildTools )
2425import Distribution.Text
2526
26−main :: IO ()
27−main = readHackage >>= runParIO . generatePackageSet
27+-- | A variant of 'readHackage' that adds the SHA256 digest of the
28+-- original Cabal file to the parsed 'GenericPackageDescription'. That
29+-- hash is required to build packages with an "edited" cabal file,
30+-- because Nix needs to download the edited file and patch it into the
31+-- original tarball.
2832
29−getEditedCabalFileHash :: String -> Version -> IO String
30−getEditedCabalFileHash name version =
31− fmap (maybe failure (derivHash . fst)) (runMaybeT $ fetchWith (False,"url",[]) srcspec)
33+readHashedHackage :: IO Hackage
34+readHashedHackage = fmap parseUnparsedHackage Unparsed.readHackage
3235 where
33− url = "mirror://hackage/" ++ pkgid ++ "/" ++ name ++ ".cabal"
34− srcspec = Source url "" Nothing
35− pkgid = name ++ "-" ++ display version
36− failure = fail $ "cannot determine edited cabal file hash for " ++ pkgid
36+ parseUnparsedHackage :: Unparsed.Hackage -> Hackage
37+ parseUnparsedHackage = Map.mapWithKey (Map.mapWithKey . parsePackage)
38+
39+ parsePackage :: String -> Version -> ByteString -> GenericPackageDescription
40+ parsePackage name version buf =
41+ let pkg = Unparsed.parsePackage name version buf
42+ hash = showDigest (sha256 buf)
43+ in
44+ pkg { packageDescription = (packageDescription pkg) {
45+ customFieldsPD = ("x-cabal-file-hash", hash) : (customFieldsPD (packageDescription pkg))
46+ }
47+ }
48+
49+main :: IO ()
50+main = readHashedHackage >>= runParIO . generatePackageSet
3751
3852nixAttr :: String -> Version -> String
3953nixAttr name _ = name -- ++ "_" ++ [ if c == '.' then '_' else c | c <- display ver ]
@@ -88,10 +102,8 @@ generatePackage (name, versions) = do
88102 pkgDescription = (Map.!) versions latestVersion
89103 srcSpec <- liftIO $ sourceFromHackage Nothing (name ++ "-" ++ display latestVersion)
90104 let drv' = (cabal2nix pkgDescription) { src = srcSpec }
91− drv <- if revision drv' > 0
92− then do cabalFileHash <- liftIO $ getEditedCabalFileHash (pname drv') (version drv')
93− return $ drv' { editedCabalFile = cabalFileHash }
94− else return drv'
105+ Just cabalFileHash = lookup "x-cabal-file-hash" (customFieldsPD (packageDescription pkgDescription))
106+ drv = drv' { editedCabalFile = if revision drv' == 0 then "" else cabalFileHash }
95107 return (name, latestVersion, drv)
96108
97109-- TODO: We should obtain the list of valid attributes in Nixpkgs at