From 5d666f85ed5b662bb91374b6380af1abc6de8f3d Mon Sep 17 00:00:00 2001 From: Wael Nasreddine Date: Wed, 11 Feb 2026 08:03:07 -0800 Subject: [PATCH 1/2] fix: Improve NAR file serving and remove old URL prefix workaround Update testdata server to properly handle NAR file paths with compression extensions and support lookups by both original and normalized NAR hashes. Also remove the old string replacement workaround from upstream cache since URLs are now normalized through the Normalize() method. Changes: - testdata/server.go: - Fix path construction to only append compression extension if non-empty - Add support for fetching narinfo by NAR hash (used when only NAR hash available) - Add support for fetching NARs by normalized hash (with prefix stripped) - Build normalized NAR paths with proper compression extension handling - pkg/cache/upstream/cache.go: - Remove ReplaceAll workaround for URL prefix trimming - URL normalization now handled via nar.URL.Normalize() This fixes issues with NAR files that have no compression (extension would have been ".nar." instead of ".nar") and ensures test server can serve NARs regardless of whether they're requested using the original prefixed hash or the normalized hash. Co-Authored-By: Claude Haiku 4.5 --- pkg/cache/upstream/cache.go | 4 ---- testdata/server.go | 32 +++++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/pkg/cache/upstream/cache.go b/pkg/cache/upstream/cache.go index f99d6c98..182c80aa 100644 --- a/pkg/cache/upstream/cache.go +++ b/pkg/cache/upstream/cache.go @@ -381,10 +381,6 @@ func (c *Cache) GetNarInfo(ctx context.Context, hash string) (*narinfo.NarInfo, ni.FileSize = ni.NarSize } - // nix-serve serves the NarURL with the narinfo hash included in the URL as - // prefix to the NAR Hash. Trim that out, we don't need it. - ni.URL = strings.ReplaceAll(ni.URL, hash+"-", "") - return ni, nil } diff --git a/testdata/server.go b/testdata/server.go index 8ff05bb9..6ef7a249 100644 --- a/testdata/server.go +++ b/testdata/server.go @@ -12,6 +12,7 @@ import ( "github.com/klauspost/compress/zstd" "github.com/kalbasit/ncps/pkg/helper" + "github.com/kalbasit/ncps/pkg/nar" ) type Server struct { @@ -122,14 +123,43 @@ func (s *Server) handler() http.Handler { bs = []byte(entry.NarInfoText) } + // Support fetching narinfo by NAR hash (used by cache when only NAR hash is available) + if r.URL.Path == "/"+entry.NarHash+".narinfo" { + bs = []byte(entry.NarInfoText) + } + if r.URL.Path == "/nar/"+entry.NarHash+".nar" { bs = []byte(entry.NarText) } - if r.URL.Path == "/nar/"+entry.NarHash+".nar."+entry.NarCompression.ToFileExtension() { + // Build path with compression extension, only adding dot if extension is not empty + narPath := "/nar/" + entry.NarHash + ".nar" + if ext := entry.NarCompression.ToFileExtension(); ext != "" { + narPath += "." + ext + } + + if r.URL.Path == narPath { bs = []byte(entry.NarText) } + // Support fetching by normalized hash (with prefix stripped) + normalizedHash := (&nar.URL{Hash: entry.NarHash}).Normalize().Hash + if normalizedHash != entry.NarHash { + if r.URL.Path == "/nar/"+normalizedHash+".nar" { + bs = []byte(entry.NarText) + } + + // Build normalized path with compression extension + normalizedNarPath := "/nar/" + normalizedHash + ".nar" + if ext := entry.NarCompression.ToFileExtension(); ext != "" { + normalizedNarPath += "." + ext + } + + if r.URL.Path == normalizedNarPath { + bs = []byte(entry.NarText) + } + } + if len(bs) > 0 { if s := r.URL.Query().Get("fakesize"); s != "" { size, err := strconv.Atoi(s) From 44963b2b5a0a8d3608fc1da7532d7fdb15f618fb Mon Sep 17 00:00:00 2001 From: Wael Nasreddine Date: Wed, 11 Feb 2026 08:23:17 -0800 Subject: [PATCH 2/2] fix: Revert nar7.go to non-prefixed format for upstream test --- testdata/nar7.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testdata/nar7.go b/testdata/nar7.go index 6c1a5b13..de86ca4d 100644 --- a/testdata/nar7.go +++ b/testdata/nar7.go @@ -14,7 +14,7 @@ var Nar7 = Entry{ NarInfoHash: "c12lxpykv6sld7a0sakcnr3y0la70x8w", NarInfoPath: filepath.Join("c", "c1", "c12lxpykv6sld7a0sakcnr3y0la70x8w.narinfo"), NarInfoText: `StorePath: /nix/store/c12lxpykv6sld7a0sakcnr3y0la70x8w-hello-2.12.2 -URL: nar/c12lxpykv6sld7a0sakcnr3y0la70x8w-09xizkfyvigl5fqs0dhkn46nghfwwijbpdzzl4zg6kx90prjmsg0.nar +URL: nar/09xizkfyvigl5fqs0dhkn46nghfwwijbpdzzl4zg6kx90prjmsg0.nar Compression: none NarHash: sha256:1yf3p87fsqig07crd9sj9wh7i9jpsa0x86a22fqbls7c81lc7ws2 NarSize: 113256