diff --git a/src/Cabal2nix.hs b/src/Cabal2nix.hs index 9d07a9db7..ae7ba220d 100644 --- a/src/Cabal2nix.hs +++ b/src/Cabal2nix.hs @@ -164,11 +164,12 @@ pinfo = info [ P2.text "" , P2.text "Recognized URI schemes:" , P2.text "" - , P2.text " cabal://pkgname-pkgversion download the specified package from Hackage" - , P2.text " cabal://pkgname download latest version of this package from Hackage" - , P2.text " file:///local/path load the Cabal file from the local disk" - , P2.text " /local/path abbreviated version of file URI" - , P2.text " download the source from the specified repository" + , P2.text " cabal://pkgname-pkgversion@pkgrevision download the specified package from Hackage, use revision N if pkgrevision is 'rev:N' or use revision with cabal file SHA256 equal to S with pkgrevision specified as 'sha256:S,SZ (SZ part is being ignored)'" + , P2.text " cabal://pkgname-pkgversion download the specified package from Hackage, use latest revision" + , P2.text " cabal://pkgname download latest version of this package from Hackage" + , P2.text " file:///local/path load the Cabal file from the local disk" + , P2.text " /local/path abbreviated version of file URI" + , P2.text " download the source from the specified repository" , P2.text "" , P2.fillSep (map P2.text (words ( "If the URI refers to a cabal file, information for building the package " ++ "will be retrieved from that file, but hackage will be used as a source " diff --git a/src/Distribution/Nixpkgs/Haskell/Hackage.hs b/src/Distribution/Nixpkgs/Haskell/Hackage.hs index 4ed8aa505..2f3ba1feb 100644 --- a/src/Distribution/Nixpkgs/Haskell/Hackage.hs +++ b/src/Distribution/Nixpkgs/Haskell/Hackage.hs @@ -1,9 +1,11 @@ module Distribution.Nixpkgs.Haskell.Hackage - ( HackageDB, PackageData, VersionData(..) + ( HackageDB, PackageData, VersionData(..), NixSha256 , hackageTarball, readTarball, parsePackageData ) where +import qualified Data.List.NonEmpty as NE +import Data.List.NonEmpty (NonEmpty) import Data.Map as Map import qualified Distribution.Hackage.DB.Parsed as P import Distribution.Hackage.DB.Path @@ -19,10 +21,11 @@ type HackageDB = Map PackageName PackageData type PackageData = Map Version VersionData +type NixSha256 = String + data VersionData = VersionData - { cabalFile :: !GenericPackageDescription - , cabalFileSha256 :: !String - , tarballSha256 :: !(Maybe String) + { cabalFilesWithHashes :: !(NonEmpty (NixSha256, GenericPackageDescription)) + , tarballSha256 :: !(Maybe NixSha256) } deriving (Show) @@ -37,9 +40,10 @@ parsePackageData dbu pn = mapWithKey (parseVersionData (dbu ! pn)) parseVersionData :: U.PackageData -> Version -> P.VersionData -> VersionData parseVersionData pdu v vd = VersionData - { cabalFile = P.cabalFile vd - , cabalFileSha256 = printSHA256 (digest (digestByName "sha256") file) + { cabalFilesWithHashes = cfsWithHashes , tarballSha256 = Map.lookup "sha256" (P.tarballHashes vd) } where - file = U.cabalFile (U.versions pdu ! v) + cfsWithHashes = NE.zip sha256s (P.cabalFileRevisions vd) + sha256s = NE.map (\file -> printSHA256 (digest (digestByName "sha256") file)) + (NE.fromList $ U.cabalFileRevisions (U.versions pdu ! v)) diff --git a/src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs b/src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs index 4b1183c49..85216820b 100644 --- a/src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs +++ b/src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs @@ -8,7 +8,8 @@ import Control.Monad.IO.Class import Control.Monad.Trans.Maybe import Data.Bifunctor import qualified Data.ByteString.Char8 as BS -import Data.List ( isSuffixOf, isPrefixOf ) +import Data.List ( isSuffixOf, isPrefixOf, stripPrefix ) +import qualified Data.List.NonEmpty as NE import qualified Data.Map as DB import Data.Maybe import Data.Time @@ -29,6 +30,7 @@ import System.Directory ( doesDirectoryExist, doesFileExist, createDirectoryIfMi import System.Exit ( exitFailure ) import System.FilePath ( (), (<.>) ) import System.IO +import Text.Read ( readMaybe ) import qualified Data.Text as T import qualified Data.Text.Encoding as T @@ -90,17 +92,40 @@ loadHackageDB optHackageDB optHackageSnapshot = do dbPath <- maybe DB.hackageTarball return optHackageDB DB.readTarball optHackageSnapshot dbPath +data Revision = RevisionLatest | RevisionN Int | RevisionSha256 DB.NixSha256 + fromDB :: IO DB.HackageDB -> String -> IO (Maybe DerivationSource, Cabal.GenericPackageDescription) -fromDB hackageDBIO pkg = do +fromDB hackageDBIO pkgRev = do hackageDB <- hackageDBIO vd <- maybe unknownPackageError return (DB.lookup name hackageDB >>= lookupVersion) let ds = case DB.tarballSha256 vd of Nothing -> Nothing Just hash -> Just (urlDerivationSource url hash) - return (ds, setCabalFileHash (DB.cabalFileSha256 vd) (DB.cabalFile vd)) + cabalFilesWithHashes = DB.cabalFilesWithHashes vd + (cabalFileSha256, cabalFile) = + case rev of + RevisionLatest -> NE.last cabalFilesWithHashes + RevisionN n -> case NE.drop n cabalFilesWithHashes of + [] -> fail $ "invalid Haskell package " ++ show pkg ++ " revision " ++ show n + x : _ -> x + RevisionSha256 sha -> case NE.filter ((== sha) . fst) cabalFilesWithHashes of + [] -> fail $ "invalid Haskell package " ++ show pkg ++ " revision SHA256 " ++ show sha + x : _ -> x + return (ds, setCabalFileHash cabalFileSha256 cabalFile) where + (pkg, rev) = case span (/= '@') pkgRev of + (p, "") -> (p, RevisionLatest) + (p, r) | Just nStr <- stripPrefix "@rev:" r, + Just n <- readMaybe nStr, + n >= 0 -> + (p, RevisionN n) + (p, r) | Just sha256size <- stripPrefix "@sha256:" r, + sha256hex <- takeWhile (/= ',') sha256size -> + (p, RevisionSha256 (toNixSha256 sha256hex)) + _ -> error $ "invalid Haskell package id " ++ show pkgRev + toNixSha256 = printSHA256 . packHex pkgId :: Cabal.PackageIdentifier pkgId = fromMaybe (error ("invalid Haskell package id " ++ show pkg)) (simpleParse pkg) name = Cabal.packageName pkgId