cabal2nix 2.5 → 2.6
raw patch · 6 files changed
+103/−80 lines, 6 filesdep ~hackage-dbPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: hackage-db
API changes (from Hackage documentation)
- Distribution.Nixpkgs.Haskell.Hackage: readHashedHackage :: IO Hackage
- Distribution.Nixpkgs.Haskell.Hackage: readHashedHackage' :: FilePath -> IO Hackage
+ Distribution.Nixpkgs.Haskell.Hackage: VersionData :: !GenericPackageDescription -> !String -> !(Maybe String) -> VersionData
+ Distribution.Nixpkgs.Haskell.Hackage: [cabalFileSha256] :: VersionData -> !String
+ Distribution.Nixpkgs.Haskell.Hackage: [cabalFile] :: VersionData -> !GenericPackageDescription
+ Distribution.Nixpkgs.Haskell.Hackage: [tarballSha256] :: VersionData -> !(Maybe String)
+ Distribution.Nixpkgs.Haskell.Hackage: data VersionData
+ Distribution.Nixpkgs.Haskell.Hackage: hackageTarball :: IO FilePath
+ Distribution.Nixpkgs.Haskell.Hackage: instance GHC.Show.Show Distribution.Nixpkgs.Haskell.Hackage.VersionData
+ Distribution.Nixpkgs.Haskell.Hackage: readTarball :: Maybe UTCTime -> FilePath -> IO HackageDB
+ Distribution.Nixpkgs.Haskell.Hackage: type HackageDB = Map PackageName PackageData
+ Distribution.Nixpkgs.Haskell.Hackage: type PackageData = Map Version VersionData
- Distribution.Nixpkgs.Haskell.PackageSourceSpec: getPackage :: Maybe String -> Source -> IO Package
+ Distribution.Nixpkgs.Haskell.PackageSourceSpec: getPackage :: Maybe FilePath -> Source -> IO Package
- Distribution.Nixpkgs.Haskell.PackageSourceSpec: sourceFromHackage :: Hash -> String -> String -> IO DerivationSource
+ Distribution.Nixpkgs.Haskell.PackageSourceSpec: sourceFromHackage :: Hash -> String -> FilePath -> IO DerivationSource
Files
- cabal2nix.cabal +9/−5
- src/Cabal2nix.hs +4/−2
- src/Distribution/Nixpkgs/Haskell/FromCabal/Name.hs +7/−9
- src/Distribution/Nixpkgs/Haskell/FromCabal/PostProcess.hs +3/−4
- src/Distribution/Nixpkgs/Haskell/Hackage.hs +38/−27
- src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs +42/−33
cabal2nix.cabal view
@@ -3,7 +3,7 @@ -- see: https://github.com/sol/hpack name: cabal2nix-version: 2.5+version: 2.6 synopsis: Convert Cabal files into Nix build instructions. description: Convert Cabal files into Nix build instructions. Users of Nix can install the latest version by running: .@@ -99,7 +99,7 @@ , directory , distribution-nixpkgs >= 1.1 , filepath- , hackage-db+ , hackage-db > 2 , hopenssl >= 2 , language-nix , lens@@ -108,6 +108,7 @@ , process , split , text+ , time , transformers , yaml exposed-modules:@@ -147,7 +148,7 @@ , directory , distribution-nixpkgs >= 1.1 , filepath- , hackage-db+ , hackage-db > 2 , hopenssl >= 2 , language-nix , lens@@ -156,6 +157,7 @@ , process , split , text+ , time , transformers , yaml , cabal2nix@@ -179,7 +181,7 @@ , directory , distribution-nixpkgs >= 1.1 , filepath- , hackage-db+ , hackage-db > 2 , hopenssl >= 2 , language-nix , lens@@ -188,6 +190,7 @@ , process , split , text+ , time , transformers , yaml , cabal2nix@@ -218,7 +221,7 @@ , directory , distribution-nixpkgs >= 1.1 , filepath- , hackage-db+ , hackage-db > 2 , hopenssl >= 2 , language-nix , lens@@ -227,6 +230,7 @@ , process , split , text+ , time , transformers , yaml , doctest
src/Cabal2nix.hs view
@@ -147,7 +147,7 @@ shell :: Doc shell = vcat- [ text "{ nixpkgs ? import <nixpkgs> {}, compiler ? \"default\" }:"+ [ text "{ nixpkgs ? import <nixpkgs> {}, compiler ? \"default\", doBenchmark ? false }:" , text "" , text "let" , text ""@@ -159,7 +159,9 @@ , text " then pkgs.haskellPackages" , text " else pkgs.haskell.packages.${compiler};" , text ""- , text " drv = haskellPackages.callPackage f {};"+ , text " variant = if doBenchmark then pkgs.haskell.lib.doBenchmark else pkgs.lib.id;"+ , text ""+ , text " drv = variant (haskellPackages.callPackage f {});" , text "" , text "in" , text ""
src/Distribution/Nixpkgs/Haskell/FromCabal/Name.hs view
@@ -81,6 +81,8 @@ libNixName "Imlib2" = return "imlib2" libNixName "iw" = return "wirelesstools" libNixName "jack" = return "libjack2"+libNixName "javascriptcoregtk-3.0" = return "webkitgtk24x-gtk3" -- These are the old APIs, of which 2.4 is the last provider, so map directly to that.+libNixName "javascriptcoregtk-4.0" = return "webkitgtk" -- This is the current API, so let it reference an alias for the latest version. libNixName "jpeg" = return "libjpeg" libNixName "jvm" = return "jdk" libNixName "lapack" = return "liblapack"@@ -132,25 +134,21 @@ libNixName "sodium" = return "libsodium" libNixName "sqlite3" = return "sqlite" libNixName "ssl" = return "openssl"+libNixName "statgrab" = return "libstatgrab" libNixName "stdc++" = [] -- What is that? libNixName "stdc++.dll" = [] -- What is that? libNixName "systemd-journal" = return "systemd"-libNixName "taglib_c" = return "taglib" libNixName "tag_c" = return "taglib"+libNixName "taglib_c" = return "taglib" libNixName "udev" = return "systemd"; libNixName "uuid" = return "libossp_uuid"; libNixName "wayland-client" = return "wayland" libNixName "wayland-cursor" = return "wayland" libNixName "wayland-egl" = return "mesa" libNixName "wayland-server" = return "wayland"--- These are the old APIs, of which 2.4 is the last provider, so map directly to that-libNixName "javascriptcoregtk-3.0" = return "webkitgtk24x-gtk3"-libNixName "webkitgtk-3.0" = return "webkitgtk24x-gtk3"--- This is the current API, so let it reference an alias for the latest version-libNixName "javascriptcoregtk-4.0" = return "webkitgtk"-libNixName "webkit2gtk-4.0" = return "webkitgtk"--- This package doesn't actually exist in nixpkgs at present-libNixName "webkit2gtk-web-extension-4.0" = return "webkitgtk-web-extension"+libNixName "webkit2gtk-4.0" = return "webkitgtk" -- This is the current API, so let it reference an alias for the latest version.+libNixName "webkit2gtk-web-extension-4.0" = return "webkitgtk-web-extension" -- This package doesn't actually exist in nixpkgs at present.+libNixName "webkitgtk-3.0" = return "webkitgtk24x-gtk3" -- These are the old APIs, of which 2.4 is the last provider, so map directly to that libNixName "X11" = return "libX11" libNixName "xau" = return "libXau" libNixName "Xcursor" = return "libXcursor"
src/Distribution/Nixpkgs/Haskell/FromCabal/PostProcess.hs view
@@ -84,10 +84,9 @@ , ("http-conduit", set doCheck False) -- attempts to access the network , ("imagemagick", set (libraryDepends . pkgconfig . contains (pkg "imagemagick")) True) -- https://github.com/NixOS/cabal2nix/issues/136 , ("include-file <= 0.1.0.2", set (libraryDepends . haskell . contains (bind "self.random")) True) -- https://github.com/Daniel-Diaz/include-file/issues/1- , ("jsaddle", set (dependencies . haskell . contains (bind "self.ghcjs-base")) False) , ("js-jquery", set doCheck False) -- attempts to access the network , ("libconfig", over (libraryDepends . system) (replace "config = null" (pkg "libconfig")))- , ("liquid-fixpoint", set (executableDepends . system . contains (pkg "ocaml")) True . set (testDepends . system . contains (pkg "z3")) True . set (testDepends . system . contains (pkg "nettools")) True)+ , ("liquid-fixpoint", set (executableDepends . system . contains (pkg "ocaml")) True . set (testDepends . system . contains (pkg "z3")) True . set (testDepends . system . contains (pkg "nettools")) True . set (testDepends . system . contains (pkg "git")) True . set doCheck False) , ("liquidhaskell", set (testDepends . system . contains (pkg "z3")) True) , ("lzma-clib", over (metaSection . platforms) (Set.filter (\(Platform _ os) -> os == Windows)) . set (libraryDepends . haskell . contains (bind "self.only-buildable-on-windows")) False) , ("MFlow < 4.6", set (libraryDepends . tool . contains (bind "self.cpphs")) True)@@ -235,7 +234,7 @@ agdaPostInstall :: String agdaPostInstall = unlines [ "postInstall = ''"- , " $out/bin/agda -c --no-main $(find $out/share -name Primitive.agda)"+ , " $out/bin/agda -c --no-main $(find $data/share -name Primitive.agda)" , " $out/bin/agda-mode compile" , "'';" ]@@ -243,7 +242,7 @@ agda25PostInstall :: String agda25PostInstall = unlines [ "postInstall = ''"- , " files=(\"$out/share/\"*\"-ghc-\"*\"/Agda-\"*\"/lib/prim/Agda/\"{Primitive.agda,Builtin\"/\"*.agda})"+ , " files=(\"$data/share/ghc-\"*\"/\"*\"-ghc-\"*\"/Agda-\"*\"/lib/prim/Agda/\"{Primitive.agda,Builtin\"/\"*.agda})" -- Separate loops to avoid internal error , " for f in \"''${files[@]}\" ; do" , " $out/bin/agda $f"
src/Distribution/Nixpkgs/Haskell/Hackage.hs view
@@ -1,33 +1,44 @@-module Distribution.Nixpkgs.Haskell.Hackage ( readHashedHackage, readHashedHackage', module Distribution.Hackage.DB ) where+module Distribution.Nixpkgs.Haskell.Hackage+ ( HackageDB, PackageData, VersionData(..)+ , hackageTarball, readTarball+ ) where -import Data.ByteString.Lazy ( ByteString )-import Distribution.Hackage.DB-import qualified Distribution.Hackage.DB.Parsed as Unparsed ( parsePackage )-import qualified Distribution.Hackage.DB.Unparsed as Unparsed+import Data.Map as Map+import qualified Distribution.Hackage.DB.Parsed as P+import Distribution.Hackage.DB.Path+import qualified Distribution.Hackage.DB.Unparsed as U import Distribution.Nixpkgs.Hashes-import OpenSSL.Digest ( digest, digestByName )+import Distribution.Package+import Distribution.PackageDescription+import Distribution.Version+import OpenSSL.Digest+import Data.Time --- | A variant of 'readHackage' that adds the SHA256 digest of the--- original Cabal file to the parsed 'GenericPackageDescription'. That--- hash is required to build packages with an "edited" cabal file,--- because Nix needs to download the edited file and patch it into the--- original tarball.+type HackageDB = Map PackageName PackageData -readHashedHackage :: IO Hackage-readHashedHackage = hackagePath >>= readHashedHackage'+type PackageData = Map Version VersionData -readHashedHackage' :: FilePath -> IO Hackage-readHashedHackage' = fmap parseUnparsedHackage . Unparsed.readHackage'- where- parseUnparsedHackage :: Unparsed.Hackage -> Hackage- parseUnparsedHackage = mapWithKey (mapWithKey . parsePackage)+data VersionData = VersionData+ { cabalFile :: !GenericPackageDescription+ , cabalFileSha256 :: !String+ , tarballSha256 :: !(Maybe String)+ }+ deriving (Show) - parsePackage :: String -> Version -> ByteString -> GenericPackageDescription- parsePackage name version buf =- let pkg = Unparsed.parsePackage name version buf- hash = printSHA256 (digest (digestByName "sha256") buf)- in- pkg { packageDescription = (packageDescription pkg) {- customFieldsPD = ("X-Cabal-File-Hash", hash) : customFieldsPD (packageDescription pkg)- }- }+readTarball :: Maybe UTCTime -> FilePath -> IO HackageDB+readTarball ts p = do+ dbu <- U.readTarball ts p+ let dbp = P.parseDB dbu+ return (mapWithKey (parsePackageData dbu) dbp)++parsePackageData :: U.HackageDB -> PackageName -> P.PackageData -> PackageData+parsePackageData dbu pn pd = mapWithKey (parseVersionData (dbu ! pn)) pd++parseVersionData :: U.PackageData -> Version -> P.VersionData -> VersionData+parseVersionData pdu v vd = VersionData+ { cabalFile = P.cabalFile vd+ , cabalFileSha256 = printSHA256 (digest (digestByName "sha256") file)+ , tarballSha256 = Map.lookup "sha256" (P.tarballHashes vd)+ }+ where+ file = U.cabalFile (U.versions pdu ! v)
src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs view
@@ -6,19 +6,19 @@ import Control.Monad import Control.Monad.IO.Class import Control.Monad.Trans.Maybe-import qualified Data.ByteString.Lazy.Char8 as LBS8 import Data.List ( isSuffixOf, isPrefixOf )+import qualified Data.Map as DB import Data.Maybe-import Distribution.Hackage.DB.Parsed import Distribution.Nixpkgs.Fetch import Distribution.Nixpkgs.Hashes import qualified Distribution.Nixpkgs.Haskell.Hackage as DB import qualified Distribution.Package as Cabal-import qualified Distribution.Version as Cabal import Distribution.PackageDescription import qualified Distribution.PackageDescription as Cabal+import Distribution.PackageDescription.Parse as Cabal import Distribution.Text ( simpleParse, display )-import OpenSSL.Digest ( digest, digestByName )+import Distribution.Version+import OpenSSL.Digest ( digestString, digestByName ) import System.Directory ( doesDirectoryExist, doesFileExist, createDirectoryIfMissing, getHomeDirectory, getDirectoryContents ) import System.Exit ( exitFailure ) import System.FilePath ( (</>), (<.>) )@@ -30,42 +30,48 @@ } deriving (Show) -getPackage :: Maybe String -> Source -> IO Package+getPackage :: Maybe FilePath -> Source -> IO Package getPackage optHackageDB source = do (derivSource, pkgDesc) <- fetchOrFromDB optHackageDB source flip Package pkgDesc <$> maybe (sourceFromHackage (sourceHash source) (showPackageIdentifier pkgDesc) $ sourceCabalDir source) return derivSource -fetchOrFromDB :: Maybe String -> Source -> IO (Maybe DerivationSource, Cabal.GenericPackageDescription)+fetchOrFromDB :: Maybe FilePath -> Source -> IO (Maybe DerivationSource, Cabal.GenericPackageDescription) fetchOrFromDB optHackageDB src- | "cabal://" `isPrefixOf` sourceUrl src = fmap ((,) Nothing) . fromDB optHackageDB . drop (length "cabal://") $ sourceUrl src+ | "cabal://" `isPrefixOf` sourceUrl src = fromDB optHackageDB . drop (length "cabal://") $ sourceUrl src | otherwise = do r <- fetch (\dir -> cabalFromPath (dir </> sourceCabalDir src)) src case r of- Nothing ->- hPutStrLn stderr "*** failed to fetch source. Does the URL exist?" >> exitFailure+ Nothing -> fail "Failed to fetch source. Does the URL exist?" Just (derivSource, (externalSource, pkgDesc)) -> do return (derivSource <$ guard externalSource, pkgDesc) -fromDB :: Maybe String -> String -> IO Cabal.GenericPackageDescription+fromDB :: Maybe FilePath -> String -> IO (Maybe DerivationSource, Cabal.GenericPackageDescription) fromDB optHackageDB pkg = do- pkgDesc <- (lookupVersion <=< DB.lookup name) <$> maybe DB.readHashedHackage DB.readHashedHackage' optHackageDB- case pkgDesc of- Just r -> return r- Nothing -> hPutStrLn stderr "*** no such package in the cabal database (did you run cabal update?). " >> exitFailure+ dbPath <- maybe DB.hackageTarball return optHackageDB+ db <- DB.readTarball Nothing dbPath+ vd <- maybe unknownPackageError return (DB.lookup name db >>= lookupVersion)+ let ds = case DB.tarballSha256 vd of+ Nothing -> Nothing+ Just hash -> Just (DerivationSource "url" url "" hash)+ return (ds, setCabalFileHash (DB.cabalFileSha256 vd) (DB.cabalFile vd)) where pkgId :: Cabal.PackageIdentifier pkgId = fromMaybe (error ("invalid Haskell package id " ++ show pkg)) (simpleParse pkg)- name = Cabal.unPackageName (Cabal.packageName pkgId)+ name = Cabal.packageName pkgId - version :: [Int]- version = Cabal.versionNumbers $ Cabal.packageVersion pkgId+ unknownPackageError = fail "No such package in the cabal database. Did you run cabal update?" - lookupVersion :: DB.Map DB.Version Cabal.GenericPackageDescription -> Maybe Cabal.GenericPackageDescription+ url = "mirror://hackage/" ++ display pkgId ++ ".tar.gz"++ version :: Version+ version = Cabal.packageVersion pkgId++ lookupVersion :: DB.Map Version DB.VersionData -> Maybe DB.VersionData -- No version is specified, pick latest one- lookupVersion m | [] <- version = fmap snd . listToMaybe $ DB.toDescList m- lookupVersion m = DB.lookup (DB.makeVersion version) m+ lookupVersion m | version == nullVersion = fmap snd (listToMaybe (DB.toDescList m))+ lookupVersion m = DB.lookup version m -readFileMay :: String -> IO (Maybe String)+readFileMay :: FilePath -> IO (Maybe String) readFileMay file = do e <- doesFileExist file if e@@ -79,7 +85,7 @@ createDirectoryIfMissing True cacheDir return $ cacheDir </> pid <.> "sha256" -sourceFromHackage :: Hash -> String -> String -> IO DerivationSource+sourceFromHackage :: Hash -> String -> FilePath -> IO DerivationSource sourceFromHackage optHash pkgId cabalDir = do cacheFile <- hashCachePath pkgId cachedHash <-@@ -135,7 +141,7 @@ cabals <- liftIO $ getDirectoryContents dir >>= filterM doesFileExist . map (dir </>) . filter (".cabal" `isSuffixOf`) case cabals of [cabalFile] -> cabalFromFile True cabalFile- _ -> liftIO $ hPutStrLn stderr ("*** found zero or more than one cabal file (" ++ show cabals ++ "). Exiting.") >> exitFailure+ _ -> liftIO $ fail ("Found zero or more than one cabal files: " ++ show cabals ++ ". Exiting.") handleIO :: (Exception.IOException -> IO a) -> IO a -> IO a handleIO = Exception.handle@@ -147,13 +153,16 @@ -- wrap the whole block in `catchIO`, because of lazy IO. The `case` will force -- the reading of the file, so we will always catch the expression here. MaybeT $ handleIO (\err -> Nothing <$ hPutStrLn stderr ("*** parsing cabal file: " ++ show err)) $ do- buf <- LBS8.readFile file- let hash = printSHA256 (digest (digestByName "sha256") buf)- case parsePackage' buf of- Left msg -> if failHard- then fail ("*** cannot parse " ++ show file ++ ": " ++ msg)- else return Nothing- Right pkg -> do return $ Just $ pkg { packageDescription = (packageDescription pkg) {- customFieldsPD = ("X-Cabal-File-Hash", hash) : customFieldsPD (packageDescription pkg)- }- }+ buf <- readFile file+ let hash = printSHA256 (digestString (digestByName "sha256") buf)+ case parseGenericPackageDescription buf of+ ParseFailed perr -> if failHard+ then fail ("cannot parse " ++ show file ++ ": " ++ show perr)+ else return Nothing+ ParseOk _ pkg -> return $ Just $ setCabalFileHash hash pkg++setCabalFileHash :: String -> GenericPackageDescription -> GenericPackageDescription+setCabalFileHash sha256 gpd = gpd { packageDescription = (packageDescription gpd) {+ customFieldsPD = ("X-Cabal-File-Hash", sha256) : customFieldsPD (packageDescription gpd)+ }+ }