Gitea Packages Nix Store/Cache #12654

Open
opened 2025-11-02 10:17:15 -06:00 by GiteaMirror · 16 comments
Owner

Originally created by @techknowlogick on GitHub (Mar 15, 2024).

Feature Description

This is probably related to the packages cache in another ticket, but I'd specifically mention a request for a nix-store in Gitea Packages.

There are various types of nix stores (https://nixos.org/manual/nix/stable/store/types/ ). On-disk is the most common, but HTTP is another supported type. This feature request is to add support to Gitea for the HTTP store type.

I understand this may be niche and other tools such as Attic (or services such as Cachix) may be preferred. Still, I decided to raise this in a ticket to see if anyone else was interested and to discuss it.

I may close this ticket in the future without discussing it as if there is no appetite for it, then there would be no use keeping it open.

Screenshots

No response

Originally created by @techknowlogick on GitHub (Mar 15, 2024). ### Feature Description This is probably related to the packages cache in another ticket, but I'd specifically mention a request for a nix-store in Gitea Packages. There are various types of nix stores (https://nixos.org/manual/nix/stable/store/types/ ). On-disk is the most common, but HTTP is another supported type. This feature request is to add support to Gitea for the HTTP store type. I understand this may be niche and other tools such as Attic (or services such as Cachix) may be preferred. Still, I decided to raise this in a ticket to see if anyone else was interested and to discuss it. I may close this ticket in the future without discussing it as if there is no appetite for it, then there would be no use keeping it open. ### Screenshots _No response_
GiteaMirror added the topic/packagestype/proposal labels 2025-11-02 10:17:15 -06:00
Author
Owner

@mweinelt commented on GitHub (Jun 27, 2024):

Looks like the link broke, this one should be stable: https://nix.dev/manual/nix/2.22/store/types/.

Looking forward to this.

@mweinelt commented on GitHub (Jun 27, 2024): Looks like the link broke, this one should be stable: https://nix.dev/manual/nix/2.22/store/types/. Looking forward to this.
Author
Owner

@techknowlogick commented on GitHub (Jun 27, 2024):

Thanks @mweinelt! It's funny you checked in on this issue today, as I've been deep in the docs this past week thinking about how best to implement it, so your timing couldn't have been any better :)

@techknowlogick commented on GitHub (Jun 27, 2024): Thanks @mweinelt! It's funny you checked in on this issue today, as I've been deep in the docs this past week thinking about how best to implement it, so your timing couldn't have been any better :)
Author
Owner

@mweinelt commented on GitHub (Jun 27, 2024):

I've reached out to a few people who developed self-hostable binary caches. They asked me to poke them again tomorrow. Some quick notes though:

  • Writing to a HTTP based store works through PUT requests issued e.g. by nix copy
  • Garbage collection could be tricky
  • A cache usable by nix should provide signing functionality
@mweinelt commented on GitHub (Jun 27, 2024): I've reached out to a few people who developed self-hostable binary caches. They asked me to poke them again tomorrow. Some quick notes though: - Writing to a HTTP based store works through PUT requests issued e.g. by `nix copy` - Garbage collection could be tricky - A cache usable by nix should provide signing functionality
Author
Owner

@techknowlogick commented on GitHub (Jun 28, 2024):

@mweinelt that's great! Advice from you and them is greatly appreciated :)
I agree regarding GC being tricky.
For pushing to the store, the logic for handling that is already pretty much in place with "generic packages," and new routes can be added for a Nix store package type to handle that.
I'm browsing Attic as a reference, as it has that managed signing part. Its global dedupe is definitely something that would be very useful, too.

@techknowlogick commented on GitHub (Jun 28, 2024): @mweinelt that's great! Advice from you and them is greatly appreciated :) I agree regarding GC being tricky. For pushing to the store, the logic for handling that is already pretty much in place with "generic packages," and new routes can be added for a Nix store package type to handle that. I'm browsing Attic as a reference, as it has that managed signing part. Its global dedupe is definitely something that would be very useful, too.
Author
Owner

@mweinelt commented on GitHub (Jun 30, 2024):

Btw: I'm currently using the attic-action, which integrates nicely with gitea/forgejo.

https://github.com/ryanccn/attic-action/blob/main/src/utils.ts#L6

@mweinelt commented on GitHub (Jun 30, 2024): Btw: I'm currently using the attic-action, which integrates nicely with gitea/forgejo. https://github.com/ryanccn/attic-action/blob/main/src/utils.ts#L6
Author
Owner

@Mic92 commented on GitHub (Jul 1, 2024):

For reference this is how fetching packages from a nix binary cache works (With extra details for non-nix users).

First Nix evaluates a package Nix expression and compute the path in /nix/store based on all the dependencies and the build recipe. Here an example for the GNU hello package.

$ nix-instantiate . -A hello
/nix/store/zc6dkvmkg2vc629hmwh00ffb68m1dl5i-hello-2.12.1.drv

The build description of a package is called derivation and has the .drv extension
We can parse this file to see in which location the nix package will install the final package.
The installation path is also called store path of a package.

$ nix show-derivation /nix/store/zc6dkvmkg2vc629hmwh00ffb68m1dl5i-hello-2.12.1.drv | jq '.[] | .outputs'
{
  "out": {
    "path": "/nix/store/26hfx324n1rbz24024h041d13ip5j42f-hello-2.12.1"
  }
}

To not build all binaries locally, Nix also allows to fetch binaries from a binary cache. This is also called binary substituter. Substitution is done by checking if the binary cache knows the any package that has the same hash as what nix computed for the store path.
The check is done in two phases. First Nix checks if the binary cache has a .narinfo file:

For our hello package the lookup looks like this:

$ curl https://cache.nixos.org/26hfx324n1rbz24024h041d13ip5j42f.narinfo
StorePath: /nix/store/26hfx324n1rbz24024h041d13ip5j42f-hello-2.12.1
URL: nar/0j1pf9gd4pf76kd2g3px23p5vxihmv57sy0m4mf212vhzxljzj23.nar.xz
Compression: xz
FileHash: sha256:0j1pf9gd4pf76kd2g3px23p5vxihmv57sy0m4mf212vhzxljzj23
FileSize: 50212
NarHash: sha256:05zj4kw49i1cw5zy2z77gls1a9fka6i4ggrmf5xxs0ndmzy48535
NarSize: 226560
References: 26hfx324n1rbz24024h041d13ip5j42f-hello-2.12.1 dbwp0scbb0rk78m636sb7cvycz8xzgyh-glibc-2.39-52
Deriver: zc6dkvmkg2vc629hmwh00ffb68m1dl5i-hello-2.12.1.drv
Sig: cache.nixos.org-1:Bv5hRLztenuCx4avxuUpIq9p4krpPz3bBFe9BvrHXSvdyzrsnbunrNIrueJ981SgNP51O5W51N8UaKXiag8nCQ==

The narinfo tells us

  • where we can find the actual file (https://cache.nixos.org/nar/0j1pf9gd4pf76kd2g3px23p5vxihmv57sy0m4mf212vhzxljzj23.nar.xz),
  • how the package is compressed (xz for cache.nixos.org),
  • what other runtime dependencies this package has (References field),
  • an ed25519 signature that is computed over the nar serialized archive of the file or directory (the nar format is explained in a bit, optional but something an internet-exposed binary cache should have)
  • The compressed size and hash (FileHash/FileSize, this is optional)
  • Uncompressed size and hash (NarHash/NarSize)
  • And what derivation file this package was built from (Deriver, also optional)

Once the narinfo was returned instead of a 404, nix will try to download the package itself.
In our example: https://cache.nixos.org/nar/0j1pf9gd4pf76kd2g3px23p5vxihmv57sy0m4mf212vhzxljzj23.nar.xz
The package is serialized in the NAR format. A NAR is quite similar to the tar format with one major difference: All paths are sorted lexically in it to ensure that the NAR is reproducible.
Apart from that it's some very simple binary format where directories/files and symlinks are concatenated with some simple length field. It doesn't encode any file ownership and the only permission it can encode is the executable bits for files. I have a Rust implementation here, if someone is interested in it: 83c384cd38/harmonia/src/nar.rs (L274)
I believe go-nix also has a go implementation of it.

Now if you do want to upload packages via http, you would do something like:

nix copy --to "http://cache.thalheim.io" /nix/store/qzq2psyvky9xblp5j3qf827bm1sjrf2m-example-unfree-package-1.0

This would than result in nix first uploading the package in nar format to nar/<hash>.nar.<compression-ext> using HTTP Put and than in the corresponding .narinfo file.

Other notable files

nix-cache-info

This file must exist or otherwise nix doesn't recognize a webserver as a binary cache:

$ curl https://cache.nixos.org/nix-cache-info
StoreDir: /nix/store
WantMassQuery: 1
Priority: 30

StoreDir is here the prefix that all packages are installed to. Priority defines which binary cache should be looked up first. WantMassQuery denotes whether this store can be queried efficiently for lookups - no idea actually what this means.

nar listing files

Similar to narinfo files, the official binary cache also implements file listings of a package.
This is for example used by the nix-index command line utility.
The format here is json. Here is an example request for the hello package above:

curl https://cache.nixos.org/26hfx324n1rbz24024h041d13ip5j42f.ls

A binary cache can choose to no implement this.

@Mic92 commented on GitHub (Jul 1, 2024): For reference this is how fetching packages from a nix binary cache works (With extra details for non-nix users). First Nix evaluates a package Nix expression and compute the path in /nix/store based on all the dependencies and the build recipe. Here an example for the GNU hello package. ```command $ nix-instantiate . -A hello /nix/store/zc6dkvmkg2vc629hmwh00ffb68m1dl5i-hello-2.12.1.drv ``` The build description of a package is called derivation and has the .drv extension We can parse this file to see in which location the nix package will install the final package. The installation path is also called store path of a package. ```command $ nix show-derivation /nix/store/zc6dkvmkg2vc629hmwh00ffb68m1dl5i-hello-2.12.1.drv | jq '.[] | .outputs' { "out": { "path": "/nix/store/26hfx324n1rbz24024h041d13ip5j42f-hello-2.12.1" } } ``` To not build all binaries locally, Nix also allows to fetch binaries from a binary cache. This is also called binary substituter. Substitution is done by checking if the binary cache knows the any package that has the same hash as what nix computed for the store path. The check is done in two phases. First Nix checks if the binary cache has a .narinfo file: For our hello package the lookup looks like this: ``` $ curl https://cache.nixos.org/26hfx324n1rbz24024h041d13ip5j42f.narinfo StorePath: /nix/store/26hfx324n1rbz24024h041d13ip5j42f-hello-2.12.1 URL: nar/0j1pf9gd4pf76kd2g3px23p5vxihmv57sy0m4mf212vhzxljzj23.nar.xz Compression: xz FileHash: sha256:0j1pf9gd4pf76kd2g3px23p5vxihmv57sy0m4mf212vhzxljzj23 FileSize: 50212 NarHash: sha256:05zj4kw49i1cw5zy2z77gls1a9fka6i4ggrmf5xxs0ndmzy48535 NarSize: 226560 References: 26hfx324n1rbz24024h041d13ip5j42f-hello-2.12.1 dbwp0scbb0rk78m636sb7cvycz8xzgyh-glibc-2.39-52 Deriver: zc6dkvmkg2vc629hmwh00ffb68m1dl5i-hello-2.12.1.drv Sig: cache.nixos.org-1:Bv5hRLztenuCx4avxuUpIq9p4krpPz3bBFe9BvrHXSvdyzrsnbunrNIrueJ981SgNP51O5W51N8UaKXiag8nCQ== ``` The narinfo tells us * where we can find the actual file (https://cache.nixos.org/nar/0j1pf9gd4pf76kd2g3px23p5vxihmv57sy0m4mf212vhzxljzj23.nar.xz), * how the package is compressed (xz for cache.nixos.org), * what other runtime dependencies this package has (References field), * an ed25519 signature that is computed over the nar serialized archive of the file or directory (the nar format is explained in a bit, optional but something an internet-exposed binary cache should have) * The compressed size and hash (FileHash/FileSize, this is optional) * Uncompressed size and hash (NarHash/NarSize) * And what derivation file this package was built from (Deriver, also optional) Once the narinfo was returned instead of a 404, nix will try to download the package itself. In our example: https://cache.nixos.org/nar/0j1pf9gd4pf76kd2g3px23p5vxihmv57sy0m4mf212vhzxljzj23.nar.xz The package is serialized in the NAR format. A NAR is quite similar to the tar format with one major difference: All paths are sorted lexically in it to ensure that the NAR is reproducible. Apart from that it's some very simple binary format where directories/files and symlinks are concatenated with some simple length field. It doesn't encode any file ownership and the only permission it can encode is the executable bits for files. I have a Rust implementation here, if someone is interested in it: https://github.com/nix-community/harmonia/blob/83c384cd38d03906dd54218658e86e53a45e94cf/harmonia/src/nar.rs#L274 I believe go-nix also has a go implementation of it. Now if you do want to upload packages via http, you would do something like: ``` nix copy --to "http://cache.thalheim.io" /nix/store/qzq2psyvky9xblp5j3qf827bm1sjrf2m-example-unfree-package-1.0 ``` This would than result in nix first uploading the package in nar format to `nar/<hash>.nar.<compression-ext>` using HTTP Put and than in the corresponding `.narinfo` file. ## Other notable files ### nix-cache-info This file must exist or otherwise nix doesn't recognize a webserver as a binary cache: ``` $ curl https://cache.nixos.org/nix-cache-info StoreDir: /nix/store WantMassQuery: 1 Priority: 30 ``` StoreDir is here the prefix that all packages are installed to. Priority defines which binary cache should be looked up first. WantMassQuery denotes whether this store can be queried efficiently for lookups - no idea actually what this means. ### nar listing files Similar to narinfo files, the official binary cache also implements file listings of a package. This is for example used by the nix-index command line utility. The format here is json. Here is an example request for the hello package above: ``` curl https://cache.nixos.org/26hfx324n1rbz24024h041d13ip5j42f.ls ``` A binary cache can choose to no implement this.
Author
Owner

@Mic92 commented on GitHub (Jul 1, 2024):

I'm browsing Attic as a reference, as it has that managed signing part. Its global dedupe is definitely something that would be very useful, too.

De-duplication is quite tricky to implement efficiently. Also attic still seems to have performance problems with it, when I tested it. Maybe start with something simpler except you have a good understanding of the underlying algorithms.

@Mic92 commented on GitHub (Jul 1, 2024): > I'm browsing Attic as a reference, as it has that managed signing part. Its global dedupe is definitely something that would be very useful, too. De-duplication is quite tricky to implement efficiently. Also attic still seems to have performance problems with it, when I tested it. Maybe start with something simpler except you have a good understanding of the underlying algorithms.
Author
Owner

@Mic92 commented on GitHub (Jul 1, 2024):

@mweinelt that's great! Advice from you and them is greatly appreciated :) I agree regarding GC being tricky.

I believe @picnoir implemented this for s3. Maybe he can give some insights what the best way to implement is.

@Mic92 commented on GitHub (Jul 1, 2024): > @mweinelt that's great! Advice from you and them is greatly appreciated :) I agree regarding GC being tricky. I believe @picnoir implemented this for s3. Maybe he can give some insights what the best way to implement is.
Author
Owner

@techknowlogick commented on GitHub (Jan 4, 2025):

Thanks for these details @Mic92 (related, thank you for your review/merge of my PR to your nix-fast-build repo). I have been looking into your details above, and that of other implementations (in the case of uploading, as attic and cachix both have service specific CLIs to do this rather than a nix-copy).

I'll definitely skip gc and dedupe for an initial implementation.

@techknowlogick commented on GitHub (Jan 4, 2025): Thanks for these details @Mic92 (related, thank you for your review/merge of my PR to your `nix-fast-build` repo). I have been looking into your details above, and that of other implementations (in the case of uploading, as attic and cachix both have service specific CLIs to do this rather than a nix-copy). I'll definitely skip gc and dedupe for an initial implementation.
Author
Owner

@Mic92 commented on GitHub (Jan 4, 2025):

https://github.com/Mic92/niks3 I also started a GC implementation for S3 and need to write an upload client next.

@Mic92 commented on GitHub (Jan 4, 2025): https://github.com/Mic92/niks3 I also started a GC implementation for S3 and need to write an upload client next.
Author
Owner

@techknowlogick commented on GitHub (Jul 28, 2025):

I've been working on this for a while now. Thanks @Mic92 and @mweinelt for your help on this. I might submit a talk to NixCon EU and talk about my lessons learned from building this. If I do end up going, I owe you both a cup of tea :)

Hopefully, I'll be able to put together a PR for this soon. The code is currently in a bit of disarray, as I aimed for it to work first, and then, once it worked, it could be cleaned up.

Image Image
@techknowlogick commented on GitHub (Jul 28, 2025): I've been working on this for a while now. Thanks @Mic92 and @mweinelt for your help on this. I might submit a talk to NixCon EU and talk about my lessons learned from building this. If I do end up going, I owe you both a cup of tea :) Hopefully, I'll be able to put together a PR for this soon. The code is currently in a bit of disarray, as I aimed for it to work first, and then, once it worked, it could be cleaned up. <img width="2144" height="212" alt="Image" src="https://github.com/user-attachments/assets/10cac356-c1ed-4e0b-9ba6-f2839e331e3c" /> <img width="2866" height="1012" alt="Image" src="https://github.com/user-attachments/assets/42395777-8601-411d-b35b-30fa2756cadb" />
Author
Owner

@Mic92 commented on GitHub (Jul 28, 2025):

I've been working on this for a while now. Thanks @Mic92 and @mweinelt for your help on this. I might submit a talk to NixCon EU and talk about my lessons learned from building this. If I do end up going, I owe you both a cup of tea :)

Hopefully, I'll be able to put together a PR for this soon. The code is currently in a bit of disarray, as I aimed for it to work first, and then, once it worked, it could be cleaned up.

Nice looking forward to the talk.

@Mic92 commented on GitHub (Jul 28, 2025): > I've been working on this for a while now. Thanks [@Mic92](https://github.com/Mic92) and [@mweinelt](https://github.com/mweinelt) for your help on this. I might submit a talk to NixCon EU and talk about my lessons learned from building this. If I do end up going, I owe you both a cup of tea :) > > Hopefully, I'll be able to put together a PR for this soon. The code is currently in a bit of disarray, as I aimed for it to work first, and then, once it worked, it could be cleaned up. Nice looking forward to the talk.
Author
Owner

@Mic92 commented on GitHub (Aug 8, 2025):

https://talks.nixcon.org/nixcon-2025/talk/SHJ7FR/

@Mic92 commented on GitHub (Aug 8, 2025): https://talks.nixcon.org/nixcon-2025/talk/SHJ7FR/
Author
Owner

@mweinelt commented on GitHub (Aug 8, 2025):

That talk will sadly not be recorded.

@mweinelt commented on GitHub (Aug 8, 2025): That talk will sadly not be recorded.
Author
Owner

@techknowlogick commented on GitHub (Sep 6, 2025):

@mweinelt It's been over a year since I last gave a talk, and so I didn't want any evidence in case I flubbed anything 😆 I think it went well though, so perhaps if I present another one I'll be ok with it being recorded. I did list you among my shout-outs at the end as a thanks for helping me on this journey. I did have a nice chat w/ @Mic92 afterwards.

@techknowlogick commented on GitHub (Sep 6, 2025): @mweinelt It's been over a year since I last gave a talk, and so I didn't want any evidence in case I flubbed anything 😆 I think it went well though, so perhaps if I present another one I'll be ok with it being recorded. I did list you among my shout-outs at the end as a thanks for helping me on this journey. I did have a nice chat w/ @Mic92 afterwards.
Author
Owner

@Mic92 commented on GitHub (Sep 6, 2025):

@techknowlogick we should have a chat again at some point again to talk about GC. Maybe when I got my reference implementation into production.

@Mic92 commented on GitHub (Sep 6, 2025): @techknowlogick we should have a chat again at some point again to talk about GC. Maybe when I got my reference implementation into production.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/gitea#12654