From dec85fecebb43a51f79f3dae83220daa358de0b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Tue, 28 May 2024 16:54:20 +0200 Subject: [PATCH] patch gitea to support nix links --- ...-tarball-link-to-archive-download-he.patch | 120 ++++++++++++++++++ pkgs/gitea/default.nix | 1 + 2 files changed, 121 insertions(+) create mode 100644 pkgs/gitea/0001-Add-an-immutable-tarball-link-to-archive-download-he.patch diff --git a/pkgs/gitea/0001-Add-an-immutable-tarball-link-to-archive-download-he.patch b/pkgs/gitea/0001-Add-an-immutable-tarball-link-to-archive-download-he.patch new file mode 100644 index 0000000..4594d0a --- /dev/null +++ b/pkgs/gitea/0001-Add-an-immutable-tarball-link-to-archive-download-he.patch @@ -0,0 +1,120 @@ +From dd2ccf4ff923757b81088e27e362e3fdb222c9d3 Mon Sep 17 00:00:00 2001 +From: Jade Lovelace +Date: Tue, 28 May 2024 16:36:25 +0200 +Subject: [PATCH] Add an immutable tarball link to archive download headers for + Nix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows `nix flake metadata` and nix in general to lock a *branch* +tarball link in a manner that causes it to fetch the correct commit even +if the branch is updated with a newer version. + +For further context, Nix flakes are a feature that, among other things, +allows for "inputs" that are "github:someuser/somerepo", +"https://some-tarball-service/some-tarball.tar.gz", +"sourcehut:~meow/nya" or similar. This feature allows our users to fetch +tarballs of git-based inputs to their builds rather than using git to +fetch them, saving significant download time. + +There is presently no gitea or forgejo specific fetcher in Nix, and we +don't particularly wish to have one. Ideally (as a developer on a Nix +implementation myself) we could just use the generic tarball fetcher and +not add specific forgejo support, but to do so, we need additional +metadata to know which commit a given *branch* tarball represents, which +is the purpose of the Link header added here. + +The result of this patch is that a Nix user can specify `inputs.something.url = +"https://forgejo-host/some/project/archive/main.tar.gz"` in flake.nix +and get a link to some concrete tarball for the actual commit in the +lock file, then when they run `nix flake update` in the future, they +will get the latest commit in that branch. + +Example of it working locally: + + » nix flake metadata --refresh 'http://localhost:3000/api/v1/repos/jade/cats/archive/main.tar.gz?dir=configs/nix' +Resolved URL: http://localhost:3000/api/v1/repos/jade/cats/archive/main.tar.gz?dir=configs/nix +Locked URL: http://localhost:3000/api/v1/repos/jade/cats/archive/804ede182b6b66469b23ea4d21eece52766b7a06.tar.gz?dir=configs +/nix&narHash=sha256-yP7KkDVfuixZzs0fsqhSETXFC0y8m6nmPLw2GrAMxKQ%3D +Description: Computers with the nixos +Path: /nix/store/s856c6yqghyan4v0zy6jj19ksv0q22nx-source +Revision: 804ede182b6b66469b23ea4d21eece52766b7a06 +Last modified: 2024-05-02 00:48:32 + +For details on the header value, see: +https://github.com/nixos/nix/blob/56763ff918eb308db23080e560ed2ea3e00c80a7/doc/manual/src/protocols/tarball-fetcher.md + +Signed-off-by: Jörg Thalheim +--- + routers/api/v1/repo/file.go | 6 ++++++ + routers/web/repo/repo.go | 6 ++++++ + tests/integration/api_repo_archive_test.go | 11 +++++++++++ + 3 files changed, 23 insertions(+) + +diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go +index 156033f58a..b7ad63af08 100644 +--- a/routers/api/v1/repo/file.go ++++ b/routers/api/v1/repo/file.go +@@ -319,6 +319,12 @@ func archiveDownload(ctx *context.APIContext) { + func download(ctx *context.APIContext, archiveName string, archiver *repo_model.RepoArchiver) { + downloadName := ctx.Repo.Repository.Name + "-" + archiveName + ++ // Add nix format link header so tarballs lock correctly: ++ // https://github.com/nixos/nix/blob/56763ff918eb308db23080e560ed2ea3e00c80a7/doc/manual/src/protocols/tarball-fetcher.md ++ ctx.Resp.Header().Add("Link", fmt.Sprintf("<%s/archive/%s.tar.gz?rev=%s>; rel=\"immutable\"", ++ ctx.Repo.Repository.APIURL(), ++ archiver.CommitID, archiver.CommitID)) ++ + rPath := archiver.RelativePath() + if setting.RepoArchive.Storage.MinioConfig.ServeDirect { + // If we have a signed url (S3, object storage), redirect to this directly. +diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go +index 71c582b5f9..bb6349658f 100644 +--- a/routers/web/repo/repo.go ++++ b/routers/web/repo/repo.go +@@ -484,6 +484,12 @@ func Download(ctx *context.Context) { + func download(ctx *context.Context, archiveName string, archiver *repo_model.RepoArchiver) { + downloadName := ctx.Repo.Repository.Name + "-" + archiveName + ++ // Add nix format link header so tarballs lock correctly: ++ // https://github.com/nixos/nix/blob/56763ff918eb308db23080e560ed2ea3e00c80a7/doc/manual/src/protocols/tarball-fetcher.md ++ ctx.Resp.Header().Add("Link", fmt.Sprintf("<%s/archive/%s.tar.gz?rev=%s>; rel=\"immutable\"", ++ ctx.Repo.Repository.APIURL(), ++ archiver.CommitID, archiver.CommitID)) ++ + rPath := archiver.RelativePath() + if setting.RepoArchive.Storage.MinioConfig.ServeDirect { + // If we have a signed url (S3, object storage), redirect to this directly. +diff --git a/tests/integration/api_repo_archive_test.go b/tests/integration/api_repo_archive_test.go +index 57d3abfe84..340ff03961 100644 +--- a/tests/integration/api_repo_archive_test.go ++++ b/tests/integration/api_repo_archive_test.go +@@ -8,6 +8,7 @@ + "io" + "net/http" + "net/url" ++ "regexp" + "testing" + + auth_model "code.gitea.io/gitea/models/auth" +@@ -39,6 +40,16 @@ func TestAPIDownloadArchive(t *testing.T) { + assert.NoError(t, err) + assert.Len(t, bs, 266) + ++ // Must return a link to a commit ID as the "immutable" archive link ++ linkHeaderRe := regexp.MustCompile(`<(?Phttps?://.*/api/v1/repos/user2/repo1/archive/[a-f0-9]+\.tar\.gz.*)>; rel="immutable"`) ++ m := linkHeaderRe.FindStringSubmatch(resp.Header().Get("Link")) ++ assert.NotEmpty(t, m[1]) ++ resp = MakeRequest(t, NewRequest(t, "GET", m[1]).AddTokenAuth(token), http.StatusOK) ++ bs2, err := io.ReadAll(resp.Body) ++ assert.NoError(t, err) ++ // The locked URL should give the same bytes as the non-locked one ++ assert.EqualValues(t, bs, bs2) ++ + link, _ = url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/archive/master.bundle", user2.Name, repo.Name)) + resp = MakeRequest(t, NewRequest(t, "GET", link.String()).AddTokenAuth(token), http.StatusOK) + bs, err = io.ReadAll(resp.Body) +-- +2.44.1 + diff --git a/pkgs/gitea/default.nix b/pkgs/gitea/default.nix index a9fbdfd..223b0d7 100644 --- a/pkgs/gitea/default.nix +++ b/pkgs/gitea/default.nix @@ -3,5 +3,6 @@ gitea.overrideAttrs (old: { patches = old.patches ++ [ ./0001-add-bot-check.patch + ./0001-Add-an-immutable-tarball-link-to-archive-download-he.patch ]; })