Content addressable Haskell package management, providing for secure, reproducible acquisition of Haskell package contents and metadata.
TODO
Content below needs to be updated.
Pantry defines the following concepts:
. or .. directory
components, no newlines in filepaths, does not begin with /, no
\\ (we normalize to POSIX-style paths). A tree is identified by a
tree key (SHA256 of the tree's serialized format)..cabal file extension at the root of the
tree, and it must match the cabal file blob key. The cabal file must
be located at pkgname.cabal. Each tree can be in at most one
package, and therefore tree keys work as package keys too.Note that with the above, a tree key is all the information necessary to uniquely identify a package. However, including additional information (package name, version, cabal key) in config files may be useful for optimizations or user friendliness. If such extra information is ever included, it must be validated to concur with the package contents itself.
Packages will optionally be sourced from some location:
In order to deal with megarepos (repos and archives containing more
than one package), there is also a subdirectory for the archive and
repository cases. An empty subdir "" would be the case for a
standard repo/archive.
In order to meet the rules of a package listed above, the following logic is applied to all three types above:
Map FilePath TreeEntry (or equivalent).Map are
contained within the same directory, strip it from all of the
paths. For example, if the paths are foo/bar and foo/baz, the
paths will be reduced to bar and baz.stripPrefix to the filepaths. If the subdir
is yesod-bin and files exist called yesod-core/yesod-core.cabal
and yesod-bin/yesod-bin.cabal, the only file remaining after
subdir stripping would be yesod-bin.cabal. Note that trailing
slashes must be handled appropriately, and that an empty subdir
string results in this step being a noop.The result of all of this is that, given one of the three package locations above, we can receive a tree key which will provide an installable package. That tree key will remain immutable.
We'll get to the caching mechanism for Pantry below. However, the recommended approach for tooling is to support some kind of composite of the Pantry keys, parsed info, and raw package location. This allows for more efficient lookups when available, with a fallback when mirrors don't have the needed information.
An example:
extra-deps:
- name: foobar
version: 1.2.3.4
pantry: deadbeef # tree key
cabal-file: 12345678 # blob key
archive: https://example.com/foobar-1.2.3.4.tar.gz
It is also recommended that tooling provide an easy way to generate such complete information from, e.g., just the URL of the tarball, and that upon reading information, hashes, package names, and version numbers are all checked for correctness.
One simplistic option for Pantry would be that, every time a piece of data is needed, Pantry downloads the necessary tarball/Git repo/etc. However, this would in practice be highly wasteful, since downloading Git repos and archives just to get a single cabal file (for plan construction purposes) is overkill. Instead, here's the basic idea for how caching works:
We may also allow these Pantry mirrors to provide some kind of query interface to find out, e.g., the latest version of a package on Hackage. That's still TBD.
To work through a full example, the following three stanzas are intended to have equivalent behavior:
- archive: https://example.com/foobar-1.2.3.4.tar.gz
- name: foobar
version: 1.2.3.4
pantry: deadbeef # tree key
cabal-file: 12345678 # blob key
archive: https://example.com/foobar-1.2.3.4.tar.gz
- pantry: deadbeef
The question is: how does the first one (presumably what a user would want to enter) be resolved into the second and third? Pantry would follow this set of steps:
Map FilePath BlobKeyMap FilePath BlobKey to a binary format and take its hash to
get a tree keydeadbeef.foobar.cabal with blob key
12345678.foobar. Grab the version number (1.2.3.4).deadbeef is a valid package, and can refer to it
by tree key exclusively. However, including the other information allows us
to verify our assumptions, provide user-friendly readable data, and provide a
fallback if the package isn't in the Pantry cache.There are three more advanced cases to consider:
The following extensions are possible to address these cases:
Providing override at the client level for Pantry mirror locations is a MUST. Making it easy to run in a corporate environment is a SHOULD. Providing the fallback package locations seems easy enough that we should include it initially, but falls under a SHOULD. The federated protocol should be added on-demand.
503 followers · starred Aug 2019
114 followers · starred Nov 2021
Haskell
100.0%
Content addressable Haskell package management, providing for secure, reproducible acquisition of Haskell package contents and metadata.
TODO
Content below needs to be updated.
Pantry defines the following concepts:
. or .. directory
components, no newlines in filepaths, does not begin with /, no
\\ (we normalize to POSIX-style paths). A tree is identified by a
tree key (SHA256 of the tree's serialized format)..cabal file extension at the root of the
tree, and it must match the cabal file blob key. The cabal file must
be located at pkgname.cabal. Each tree can be in at most one
package, and therefore tree keys work as package keys too.Note that with the above, a tree key is all the information necessary to uniquely identify a package. However, including additional information (package name, version, cabal key) in config files may be useful for optimizations or user friendliness. If such extra information is ever included, it must be validated to concur with the package contents itself.
Packages will optionally be sourced from some location:
In order to deal with megarepos (repos and archives containing more
than one package), there is also a subdirectory for the archive and
repository cases. An empty subdir "" would be the case for a
standard repo/archive.
In order to meet the rules of a package listed above, the following logic is applied to all three types above:
Map FilePath TreeEntry (or equivalent).Map are
contained within the same directory, strip it from all of the
paths. For example, if the paths are foo/bar and foo/baz, the
paths will be reduced to bar and baz.stripPrefix to the filepaths. If the subdir
is yesod-bin and files exist called yesod-core/yesod-core.cabal
and yesod-bin/yesod-bin.cabal, the only file remaining after
subdir stripping would be yesod-bin.cabal. Note that trailing
slashes must be handled appropriately, and that an empty subdir
string results in this step being a noop.The result of all of this is that, given one of the three package locations above, we can receive a tree key which will provide an installable package. That tree key will remain immutable.
We'll get to the caching mechanism for Pantry below. However, the recommended approach for tooling is to support some kind of composite of the Pantry keys, parsed info, and raw package location. This allows for more efficient lookups when available, with a fallback when mirrors don't have the needed information.
An example:
extra-deps:
- name: foobar
version: 1.2.3.4
pantry: deadbeef # tree key
cabal-file: 12345678 # blob key
archive: https://example.com/foobar-1.2.3.4.tar.gz
It is also recommended that tooling provide an easy way to generate such complete information from, e.g., just the URL of the tarball, and that upon reading information, hashes, package names, and version numbers are all checked for correctness.
One simplistic option for Pantry would be that, every time a piece of data is needed, Pantry downloads the necessary tarball/Git repo/etc. However, this would in practice be highly wasteful, since downloading Git repos and archives just to get a single cabal file (for plan construction purposes) is overkill. Instead, here's the basic idea for how caching works:
We may also allow these Pantry mirrors to provide some kind of query interface to find out, e.g., the latest version of a package on Hackage. That's still TBD.
To work through a full example, the following three stanzas are intended to have equivalent behavior:
- archive: https://example.com/foobar-1.2.3.4.tar.gz
- name: foobar
version: 1.2.3.4
pantry: deadbeef # tree key
cabal-file: 12345678 # blob key
archive: https://example.com/foobar-1.2.3.4.tar.gz
- pantry: deadbeef
The question is: how does the first one (presumably what a user would want to enter) be resolved into the second and third? Pantry would follow this set of steps:
Map FilePath BlobKeyMap FilePath BlobKey to a binary format and take its hash to
get a tree keydeadbeef.foobar.cabal with blob key
12345678.foobar. Grab the version number (1.2.3.4).deadbeef is a valid package, and can refer to it
by tree key exclusively. However, including the other information allows us
to verify our assumptions, provide user-friendly readable data, and provide a
fallback if the package isn't in the Pantry cache.There are three more advanced cases to consider:
The following extensions are possible to address these cases:
Providing override at the client level for Pantry mirror locations is a MUST. Making it easy to run in a corporate environment is a SHOULD. Providing the fallback package locations seems easy enough that we should include it initially, but falls under a SHOULD. The federated protocol should be added on-demand.
503 followers · starred Aug 2019
114 followers · starred Nov 2021
Haskell
100.0%