Skip to content

Can we get a metadata file with a specific revision or hash? #1421

Open

Description

@bglgwyng

I'm currently trying to create a Nixified Haskell package set using plan.json. This is the approach I'm taking.
I need to make the process of fetching packages from Hackage using plan.json reproducible. However, there are currently these issues:

The cabal file of the network-uri package fetched through the URI like https://hackage.haskell.org/package/network-uri-2.4.2.2/network-uri-2.4.2.2.tar.gz is the originally uploaded version, not the latest revision. This is fine since the pkg-src-sha256 in plan.json also points to the hash of the original version.
I discovered that I can fetch the latest revision via https://hackage.haskell.org/package/network-uri-2.4.2.2/network-uri.cabal. The hash of that cabal file matches the pkg-cabal-sha256 in plan.json.
To make builds perfectly reproducible, I need to be able to fetch a specific version of the .cabal file rather than just the latest revision. Does Hackage currently provide a way to do this?

Activity

  1. phadej commented on Aug 7, 2025

    @phadej
    Contributor

    Yes, look e.g. at https://hackage.haskell.org/package/network-uri-2.6.4.2/revisions/

    I don't think there's url to fetch using a hash, only using a revision number.

  2. bglgwyng commented on Aug 8, 2025

    @bglgwyng
    Author

    I was aware of that page. Then, the best approach possible by now is fetching that page and parsing HTML to find out the matching revision?

  3. bglgwyng commented on Aug 8, 2025

    @bglgwyng
    Author

    I think it would be better if we have a more machine-readable format provided also.

  4. gbaz commented on Aug 8, 2025

    @gbaz
    Contributor
  5. phadej commented on Aug 8, 2025

    @phadej
    Contributor

    FWIW, the 01-index.tar locally on your machine is the most machine readable format you can have. You don't need to access Hackage at all (other than to get actual source tarballs). E.g. https://hackage-content.haskell.org/package/cabal-install-parsers-0.6.3/docs/Cabal-Index.html#v:indexMetadata constructs the latest view of the package index. PackageInfo has the revision number, so if you want you can use that to construct URLs to fetch .cabal files, alternatively you can simply embed them in the derivations.

  6. bglgwyng commented on Aug 9, 2025

    @bglgwyng
    Author

    I'm trying to emulate the cabal fetch behavior only with Nix, so I think the best approach available now is fetching /package/:pacakge/revision in JSON to get the index from the hash of the revision and applying to the .tar.gz extraction of /package/:package/:pacakge.tar.gz

  7. phadej commented on Aug 9, 2025

    @phadej
    Contributor

    I'm trying to emulate the cabal fetch

    cabal fetch doesn't not fetch .cabal files from Hackage. They come from the 01-index.tar file:

    % cabal get -v assoc
    Reading available packages of hackage.haskell.org...
    Using most recent state specified from most recent cabal update
    index-state(hackage.haskell.org) = 2025-08-02T19:59:02Z
    assoc-1.1.1 has already been downloaded.
    Unpacking to assoc-1.1.1/
    Updating assoc-1.1.1/assoc.cabal with the latest revision from the index.
    
  8. bglgwyng commented on Aug 9, 2025

    @bglgwyng
    Author

    Ah, I should say cabal get. I mean, the fetch from Hackage server behavior or cabal.

  9. bglgwyng commented on Aug 11, 2025

    @bglgwyng
    Author

    I realized that I can't fetch the revisions JSON file reliably with a hash. I mean. There's no hash for revisions JSON provided in plan.json. This makes it impossible to fetch revisions JSON from Nix's fetchurl.

    How about allowing downloading a metadata file with a specific revision with its hash? like /package/network-uri-2.6.4.2/network-uri.cabal?sha256=....? If I create a PR for this, do you think it's acceptable?

  10. ulysses4ever commented on Aug 11, 2025

    @ulysses4ever
    Contributor

    @bglgwyng your aims seem roughly similar to what Stackages people has been doing with https://github.com/commercialhaskell/all-cabal-tool and related repos (esp all-cabal-hashes). Could that help you?

  11. gbaz commented on Aug 11, 2025

    @gbaz
    Contributor

    I don't think that we would want to extend hackage with hash-based downloads -- it already provides a number of mechanisms for retrieving packages and cabal revisions both, as detailed above. Further, we know that nix can make use of these mechanisms effectively, e.g. in overrideCabal and callHackageDirect both: https://magnus.therning.org/2024-04-20-update-to-hackage-revisions-in-nix.html

    As such, modified versions of these functions could certainly be used to fetch but not build, without the need of changes on the hackage server.

  12. bglgwyng commented on Aug 12, 2025

    @bglgwyng
    Author

    @ulysses4ever @gbaz Thanks for sharing! From my understanding, both methods are based on the pre-fetched Hackage metadata before evaluating the Nix script. Aren't they?

    https://github.com/bglgwyng/plan2flake/blob/main/flake.nix#L48-L82 This is my approach, and it doesn't require any pre-fetched metadata. But it has problems I described above.

  13. gbaz commented on Aug 12, 2025

    @gbaz
    Contributor

    I'm not sure what you're getting at with pre-fetched metadata? Do you mean via use of cabal itself?

    I think a good approach could be just using the sdistTarball function from here: https://ryantm.github.io/nixpkgs/languages-frameworks/haskell/ -- that should handle revisions and versions etc for you in a fairly robust and well supported way?

  14. bglgwyng commented on Aug 12, 2025

    @bglgwyng
    Author

    Sorry, I misunderstood callHacakgeDirectly. However, it requires rev.revision to determine the metadata revision, which is missing from plan.json. Hmm... Should plan.json provide revision then, and the problem is in cabal?

  15. gbaz commented on Aug 12, 2025

    @gbaz
    Contributor

    when cabal generates a plan.json it will always use the latest metadata revision (unless it is explicitly passed timestamp telling it to do otherwise), which is also what callHackageDirectly will use, and which is available by fetching the cabal file from hackage directly. So if your code assumes the plan.json is generated in proximity (timewise) to when your code is run, then it should be safe for you to always assume the latest revision as well.

  16. bglgwyng commented on Aug 12, 2025

    @bglgwyng
    Author

    Yes. I agree. In most cases, it doesn't matter, and re-generating plan.json is a working solution. However, I want to utilize plan.json as Cargo.lock in Rust, so I'm looking for a way to fetch the specific revision in Nix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions