From 952d42fd98e2923c85ae741a436f2dc492cde1d0 Mon Sep 17 00:00:00 2001 From: sternenseemann Date: Wed, 25 Feb 2026 22:13:17 +0100 Subject: [PATCH 1/3] hackage-db/DB.Parsed: don't filter out nonpreferred versions We still want to access nonpreferred versions in our parsed DB on occasion. E.g. cabal2nix cabal://chronologique currently fails because the package is deprecated and thus no version is preferred. --- hackage-db/CHANGELOG.md | 7 +++++++ hackage-db/hackage-db.cabal | 2 +- hackage-db/src/Distribution/Hackage/DB/Parsed.hs | 11 ++--------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/hackage-db/CHANGELOG.md b/hackage-db/CHANGELOG.md index fa76e46a9..97ceeef75 100644 --- a/hackage-db/CHANGELOG.md +++ b/hackage-db/CHANGELOG.md @@ -1,5 +1,12 @@ # Revision history for hackage-db +## 2.2.0 (unreleased) + +* `Distribution.Hackage.DB.Parsed.parsePackageData` no longer filters out + package versions that are not preferred. This means that the list of + available versions will no longer differ between the `Parsed` and + `Unparsed` modules. This is a **breaking change**. + ## 2.1.3 * `hackageTarball` / `cabalStateDir` now support overriding the cabal directory diff --git a/hackage-db/hackage-db.cabal b/hackage-db/hackage-db.cabal index e53a71ce5..c6dd0e4ee 100644 --- a/hackage-db/hackage-db.cabal +++ b/hackage-db/hackage-db.cabal @@ -1,5 +1,5 @@ name: hackage-db -version: 2.1.3 +version: 2.2.0 synopsis: Access cabal-install's Hackage database via Data.Map description: This library provides convenient access to the local copy of the Hackage database that \"cabal update\" creates. Check out diff --git a/hackage-db/src/Distribution/Hackage/DB/Parsed.hs b/hackage-db/src/Distribution/Hackage/DB/Parsed.hs index c4dec6445..417dbf836 100644 --- a/hackage-db/src/Distribution/Hackage/DB/Parsed.hs +++ b/hackage-db/src/Distribution/Hackage/DB/Parsed.hs @@ -11,7 +11,6 @@ module Distribution.Hackage.DB.Parsed where import Distribution.Hackage.DB.Errors import qualified Distribution.Hackage.DB.MetaData as U import qualified Distribution.Hackage.DB.Unparsed as U -import Distribution.Hackage.DB.Utility import Codec.Archive.Tar import Control.Exception @@ -25,7 +24,6 @@ import Distribution.Package import Distribution.PackageDescription import Distribution.PackageDescription.Parsec import Distribution.Text -import Distribution.Types.PackageVersionConstraint import Distribution.Version import GHC.Generics ( Generic ) @@ -48,14 +46,9 @@ parseDB :: U.HackageDB -> HackageDB parseDB = Map.mapWithKey parsePackageData parsePackageData :: PackageName -> U.PackageData -> PackageData -parsePackageData pn (U.PackageData pv vs') = +parsePackageData pn (U.PackageData pv vs) = mapException (\e -> HackageDBPackageName pn (e :: SomeException)) $ - Map.mapWithKey (parseVersionData pn) $ - Map.filterWithKey (\v _ -> v `withinRange` vr) vs' - where - PackageVersionConstraint _ vr - | BSS.null pv = PackageVersionConstraint pn anyVersion - | otherwise = parseBS "preferred version range" pv + Map.mapWithKey (parseVersionData pn) vs parseVersionData :: PackageName -> Version -> U.VersionData -> VersionData parseVersionData pn v (U.VersionData cf m) = From 4deee2c6ed19fd47e8c5dc7cd92893d25f8cb587 Mon Sep 17 00:00:00 2001 From: sternenseemann Date: Wed, 25 Feb 2026 23:09:14 +0100 Subject: [PATCH 2/3] hackage-db/Parsed: expose preferred VersionRange and tag versions Now that we no longer filter out nonpreferred versions, users may want to do this themselves. We expose (for completeness sake and because we need to compute it anyways) the preferred VersionRange and tag every version individually for convenience. --- cabal2nix/cabal2nix.cabal | 2 +- .../Distribution/Nixpkgs/Haskell/Hackage.hs | 2 +- hackage-db/CHANGELOG.md | 10 ++++++++++ hackage-db/example/show-package-versions.hs | 2 +- hackage-db/src/Distribution/Hackage/DB.hs | 2 +- .../src/Distribution/Hackage/DB/Parsed.hs | 20 ++++++++++++++----- 6 files changed, 29 insertions(+), 9 deletions(-) diff --git a/cabal2nix/cabal2nix.cabal b/cabal2nix/cabal2nix.cabal index 35964acb5..81832c85f 100644 --- a/cabal2nix/cabal2nix.cabal +++ b/cabal2nix/cabal2nix.cabal @@ -61,7 +61,7 @@ library , directory , distribution-nixpkgs >= 1.7 && <1.8 , filepath - , hackage-db >= 2.0.1 + , hackage-db >= 2.2.0 , hopenssl >= 2 , hpack >= 0.29.6 , language-nix diff --git a/cabal2nix/src/Distribution/Nixpkgs/Haskell/Hackage.hs b/cabal2nix/src/Distribution/Nixpkgs/Haskell/Hackage.hs index 4ed8aa505..a6653f4b9 100644 --- a/cabal2nix/src/Distribution/Nixpkgs/Haskell/Hackage.hs +++ b/cabal2nix/src/Distribution/Nixpkgs/Haskell/Hackage.hs @@ -33,7 +33,7 @@ readTarball ts p = do return (mapWithKey (parsePackageData dbu) dbp) parsePackageData :: U.HackageDB -> PackageName -> P.PackageData -> PackageData -parsePackageData dbu pn = mapWithKey (parseVersionData (dbu ! pn)) +parsePackageData dbu pn = mapWithKey (parseVersionData (dbu ! pn)) . P.versions parseVersionData :: U.PackageData -> Version -> P.VersionData -> VersionData parseVersionData pdu v vd = VersionData diff --git a/hackage-db/CHANGELOG.md b/hackage-db/CHANGELOG.md index 97ceeef75..8efe62ab8 100644 --- a/hackage-db/CHANGELOG.md +++ b/hackage-db/CHANGELOG.md @@ -6,6 +6,16 @@ package versions that are not preferred. This means that the list of available versions will no longer differ between the `Parsed` and `Unparsed` modules. This is a **breaking change**. + To restore the old behavior, use the `preferred` field of `VersionData` + to filter the `versions` map (see below). +* `Distribution.Hackage.DB.Parsed.PackageData` has been changed from a type + alias to a sum type. Its previous content is the new `versions` field. + This is an **API breaking change**. +* `Distribution.Hackage.DB.Parsed.VersionData` gains a new field, `preferred` + which describes whether the package version in question matches the + `preferred-versions` range given also exposed via the `preferredVersions` + field of `Distribution.Hackage.DB.Parsed.PackageData`. + This is an **API breaking change**. ## 2.1.3 diff --git a/hackage-db/example/show-package-versions.hs b/hackage-db/example/show-package-versions.hs index 7db81dfa5..4f34f74f0 100644 --- a/hackage-db/example/show-package-versions.hs +++ b/hackage-db/example/show-package-versions.hs @@ -13,5 +13,5 @@ main = do db <- hackageTarball >>= readTarball Nothing pkgs <- getArgs forM_ pkgs $ \pkg -> do - let vs = maybe [] Map.keys (Map.lookup (mkPackageName pkg) db) + let vs = maybe [] (Map.keys . versions) (Map.lookup (mkPackageName pkg) db) putStrLn $ pkg ++ ": " ++ unwords (fmap display vs) diff --git a/hackage-db/src/Distribution/Hackage/DB.hs b/hackage-db/src/Distribution/Hackage/DB.hs index 5e096c109..85d86001d 100644 --- a/hackage-db/src/Distribution/Hackage/DB.hs +++ b/hackage-db/src/Distribution/Hackage/DB.hs @@ -5,7 +5,7 @@ -} module Distribution.Hackage.DB - ( HackageDB, PackageData, VersionData(..) + ( HackageDB, PackageData(..), VersionData(..) , readTarball, parseTarball, hackageTarball ) where diff --git a/hackage-db/src/Distribution/Hackage/DB/Parsed.hs b/hackage-db/src/Distribution/Hackage/DB/Parsed.hs index 417dbf836..934fb83ff 100644 --- a/hackage-db/src/Distribution/Hackage/DB/Parsed.hs +++ b/hackage-db/src/Distribution/Hackage/DB/Parsed.hs @@ -11,6 +11,7 @@ module Distribution.Hackage.DB.Parsed where import Distribution.Hackage.DB.Errors import qualified Distribution.Hackage.DB.MetaData as U import qualified Distribution.Hackage.DB.Unparsed as U +import Distribution.Hackage.DB.Utility import Codec.Archive.Tar import Control.Exception @@ -24,15 +25,20 @@ import Distribution.Package import Distribution.PackageDescription import Distribution.PackageDescription.Parsec import Distribution.Text +import Distribution.Types.PackageVersionConstraint import Distribution.Version import GHC.Generics ( Generic ) type HackageDB = Map PackageName PackageData -type PackageData = Map Version VersionData +data PackageData = PackageData { versions :: !(Map Version VersionData) + , preferredVersions :: !VersionRange + } + deriving (Show, Eq, Generic) data VersionData = VersionData { cabalFile :: !GenericPackageDescription , tarballHashes :: !(Map String String) + , preferred :: !Bool } deriving (Show, Eq, Generic) @@ -48,12 +54,16 @@ parseDB = Map.mapWithKey parsePackageData parsePackageData :: PackageName -> U.PackageData -> PackageData parsePackageData pn (U.PackageData pv vs) = mapException (\e -> HackageDBPackageName pn (e :: SomeException)) $ - Map.mapWithKey (parseVersionData pn) vs + PackageData (Map.mapWithKey (parseVersionData pn vr) vs) vr + where + PackageVersionConstraint _ vr + | BSS.null pv = PackageVersionConstraint pn anyVersion + | otherwise = parseBS "preferred version range" pv -parseVersionData :: PackageName -> Version -> U.VersionData -> VersionData -parseVersionData pn v (U.VersionData cf m) = +parseVersionData :: PackageName -> VersionRange -> Version -> U.VersionData -> VersionData +parseVersionData pn vr v (U.VersionData cf m) = mapException (\e -> HackageDBPackageVersion v (e :: SomeException)) $ - VersionData gpd (parseMetaData pn v m) + VersionData gpd (parseMetaData pn v m) (v `withinRange` vr) where gpd = fromMaybe (throw (InvalidCabalFile (show (pn,v)))) $ parseGenericPackageDescriptionMaybe cf From 0cca1fb12cf54b591a6a1b7b67112100dcb23939 Mon Sep 17 00:00:00 2001 From: sternenseemann Date: Wed, 25 Feb 2026 23:56:29 +0100 Subject: [PATCH 3/3] cabal2nix: avoid using a nonpreferred version when possible Before the recent changes to hackage-db, cabal2nix cabal:// (i.e. no explicit version requested) would never pick a nonpreferred version. This change restores the old behavior for packages that have preferred versions available. If none is available, we keep picking the latest one. --- cabal2nix/src/Distribution/Nixpkgs/Haskell/Hackage.hs | 11 +++++++++++ .../Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/cabal2nix/src/Distribution/Nixpkgs/Haskell/Hackage.hs b/cabal2nix/src/Distribution/Nixpkgs/Haskell/Hackage.hs index a6653f4b9..9e52beb46 100644 --- a/cabal2nix/src/Distribution/Nixpkgs/Haskell/Hackage.hs +++ b/cabal2nix/src/Distribution/Nixpkgs/Haskell/Hackage.hs @@ -1,6 +1,7 @@ module Distribution.Nixpkgs.Haskell.Hackage ( HackageDB, PackageData, VersionData(..) , hackageTarball, readTarball, parsePackageData + , latestPreferredVersion ) where @@ -23,9 +24,18 @@ data VersionData = VersionData { cabalFile :: !GenericPackageDescription , cabalFileSha256 :: !String , tarballSha256 :: !(Maybe String) + , preferred :: !Bool } deriving (Show) +-- Look up the latest preferred version. If there are no preferred versions, use the latest one. +latestPreferredVersion :: PackageData -> Maybe VersionData +latestPreferredVersion pd + | Map.null pd = Nothing -- TODO: shouldn't happen, more specific error? + | otherwise = Just $ snd $ Map.findMax (if Map.null ppd then pd else ppd) + where + ppd = Map.filter preferred pd + readTarball :: Maybe UTCTime -> FilePath -> IO HackageDB readTarball ts p = do dbu <- U.readTarball ts p @@ -40,6 +50,7 @@ parseVersionData pdu v vd = VersionData { cabalFile = P.cabalFile vd , cabalFileSha256 = printSHA256 (digest (digestByName "sha256") file) , tarballSha256 = Map.lookup "sha256" (P.tarballHashes vd) + , preferred = P.preferred vd } where file = U.cabalFile (U.versions pdu ! v) diff --git a/cabal2nix/src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs b/cabal2nix/src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs index f08ea37b8..282c3284e 100644 --- a/cabal2nix/src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs +++ b/cabal2nix/src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs @@ -139,7 +139,7 @@ fromDB hackageDBIO pkg = do lookupVersion :: DB.Map Version DB.VersionData -> Maybe DB.VersionData -- No version is specified, pick latest one - lookupVersion m | version == nullVersion = fmap snd (listToMaybe (DB.toDescList m)) + lookupVersion m | version == nullVersion = DB.latestPreferredVersion m lookupVersion m = DB.lookup version m readFileMay :: FilePath -> IO (Maybe String)