Subject: [bug#52555] [RFC PATCH 1/3] publish: Add ERIS URN to narinfo

From: pukkamustard <[email-masked]>
Date: Thu, 16 Dec 2021 16:20:34 +0000

* guix/scripts/publish.scm: (bake-narinfo+nar): Compute ERIS URN of compressed nars.
(narinfo-string): Add #:eris-urns parameter and honor it.
(store-item->recutils): Add #:eris-urn parameter and honor it.
* guix/scripts/narinfo.scm: (<narinfo>)[eris-urns]: New field.
(narinfo-maker): Handle ERIS URN.
* configure.ac: (HAVE_GUILE_ERIS): New conditional.
* gnu/packages/package-management.scm: (guix)[native-inputs]: Add guile-eris.
---
 configure.ac                        |  5 +++++
 gnu/packages/package-management.scm |  1 +
 guix/narinfo.scm                    | 10 ++++++----
 guix/scripts/publish.scm            | 31 +++++++++++++++++++++--------
 4 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/configure.ac b/configure.ac
index 341cff8fbd..72396be8aa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -170,6 +170,11 @@ GUILE_MODULE_AVAILABLE([have_guile_avahi], [(avahi)])
 AM_CONDITIONAL([HAVE_GUILE_AVAHI],
   [test "x$have_guile_avahi" = "xyes"])
 
+dnl Check for Guile-eris.
+GUILE_MODULE_AVAILABLE([have_guile_eris], [(eris)])
+AM_CONDITIONAL([HAVE_GUILE_ERIS],
+  [test "x$have_guile_eris" = "xyes"])
+
 dnl Guile-newt is used by the graphical installer.
 GUILE_MODULE_AVAILABLE([have_guile_newt], [(newt)])
 
diff --git a/gnu/packages/package-management.scm b/gnu/packages/package-management.scm
index 9496499850..5c49167782 100644
--- a/gnu/packages/package-management.scm
+++ b/gnu/packages/package-management.scm
@@ -394,6 +394,7 @@ (define code
                        ("guile-zstd" ,guile-zstd)
                        ("guile-ssh" ,guile-ssh)
                        ("guile-git" ,guile-git)
+                       ("guile-eris" ,guile-eris)
 
                        ;; XXX: Keep the development inputs here even though
                        ;; they're unnecessary, just so that 'guix environment
diff --git a/guix/narinfo.scm b/guix/narinfo.scm
index 4fc550aa6c..0972ede3c1 100644
--- a/guix/narinfo.scm
+++ b/guix/narinfo.scm
@@ -67,13 +67,14 @@ (define-module (guix narinfo)
             equivalent-narinfo?))
 
 (define-record-type <narinfo>
-  (%make-narinfo path uri-base uris compressions file-sizes file-hashes
-                 nar-hash nar-size references deriver system
+  (%make-narinfo path uri-base uris eris-urns compressions file-sizes
+                 file-hashes nar-hash nar-size references deriver system
                  signature contents)
   narinfo?
   (path         narinfo-path)
   (uri-base     narinfo-uri-base)        ;URI of the cache it originates from
   (uris         narinfo-uris)            ;list of strings
+  (eris-urns    narinfo-eris-urns)       ;list of (strings | #f)
   (compressions narinfo-compressions)    ;list of strings
   (file-sizes   narinfo-file-sizes)      ;list of (integers | #f)
   (file-hashes  narinfo-file-hashes)
@@ -134,7 +135,7 @@ (define (narinfo-signature->canonical-sexp str)
 (define (narinfo-maker str cache-url)
   "Return a narinfo constructor for narinfos originating from CACHE-URL.  STR
 must contain the original contents of a narinfo file."
-  (lambda (path urls compressions file-hashes file-sizes
+  (lambda (path urls eris-urns compressions file-hashes file-sizes
                 nar-hash nar-size references deriver system
                 signature)
     "Return a new <narinfo> object."
@@ -148,6 +149,7 @@ (define len (length urls))
                                    (string-append cache-url url)
                                    (string-append cache-url "/" url)))))
                         urls)
+                   eris-urns
                    compressions
                    (match file-sizes
                      (()        (make-list len #f))
@@ -186,7 +188,7 @@ (define* (read-narinfo port #:optional url
                      "FileHash" "FileSize" "NarHash" "NarSize"
                      "References" "Deriver" "System"
                      "Signature")
-                   '("URL" "Compression" "FileSize" "FileHash"))))
+                   '("URL" "ERIS" "Compression" "FileSize" "FileHash"))))
 
 (define (narinfo-sha256 narinfo)
   "Return the sha256 hash of NARINFO as a bytevector, or #f if NARINFO lacks a
diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm
index 6e2b4368da..8e4b90789b 100644
--- a/guix/scripts/publish.scm
+++ b/guix/scripts/publish.scm
@@ -58,6 +58,7 @@ (define-module (guix scripts publish)
   #:use-module (guix workers)
   #:use-module (guix store)
   #:use-module ((guix serialization) #:select (write-file))
+  #:use-module (eris)
   #:use-module (zlib)
   #:autoload   (lzlib) (call-with-lzip-output-port
                         make-lzip-output-port)
@@ -308,7 +309,7 @@ (define* (store-item->recutils store-item
                                #:key
                                (nar-path "nar")
                                (compression %no-compression)
-                               file-size)
+                               file-size eris-urn)
   "Return the 'Compression' and 'URL' fields of the narinfo for STORE-ITEM,
 with COMPRESSION, starting at NAR-PATH."
   (let ((url (encode-and-join-uri-path
@@ -319,19 +320,22 @@ (define* (store-item->recutils store-item
                     (($ <compression> type)
                      (list (symbol->string type))))
                 ,(basename store-item)))))
-    (format #f "URL: ~a~%Compression: ~a~%~@[FileSize: ~a~%~]"
-            url (compression-type compression) file-size)))
+    (format #f "URL: ~a~%Compression: ~a~%~@[FileSize: ~a~%~]~@[ERIS: ~a~%~]"
+            url (compression-type compression) file-size eris-urn)))
 
 (define* (narinfo-string store store-path
                          #:key (compressions (list %no-compression))
-                         (nar-path "nar") (file-sizes '()))
+                         (nar-path "nar") (file-sizes '()) (eris-urns '()))
   "Generate a narinfo key/value string for STORE-PATH; an exception is raised
 if STORE-PATH is invalid.  Produce a URL that corresponds to COMPRESSION.  The
 narinfo is signed with KEY.  NAR-PATH specifies the prefix for nar URLs.
 
 Optionally, FILE-SIZES is a list of compression/integer pairs, where the
 integer is size in bytes of the compressed NAR; it informs the client of how
-much needs to be downloaded."
+much needs to be downloaded.
+
+Optionally, ERIS-URNS is a list of compression/string pairs, where the
+string is the ERIS URN of the compressed NAR."
   (let* ((path-info  (query-path-info store store-path))
          (compressions (actual-compressions store-path compressions))
          (hash       (bytevector->nix-base32-string
@@ -352,9 +356,12 @@ (define* (narinfo-string store store-path
                              store-path
                              (map (lambda (compression)
                                     (let ((size (assoc-ref file-sizes
-                                                           compression)))
+                                                           compression))
+                                          (eris-urn (assoc-ref eris-urns
+                                                               compression)))
                                       (store-item->recutils store-path
                                                             #:file-size size
+                                                            #:eris-urn eris-urn
                                                             #:nar-path nar-path
                                                             #:compression
                                                             compression)))
@@ -632,6 +639,12 @@ (define (compressed-nar-size compression)
       (and stat
            (cons compression (stat:size stat)))))
 
+  (define (compressed-eris-urn compression)
+    (let* ((nar (nar-cache-file cache item #:compression compression))
+           (stat (stat nar #f)))
+      (and stat
+           (cons compression (call-with-input-file nar eris-encode->urn)))))
+
   (let ((compression (actual-compressions item compressions)))
 
     (for-each (cut compress-nar cache item <>) compressions)
@@ -646,11 +659,13 @@ (define (compressed-nar-size compression)
              ;; thread's connection to the store since we would end up sending
              ;; stuff concurrently on the same channel.
              (with-store store
-               (let ((sizes (filter-map compressed-nar-size compression)))
+               (let ((sizes (filter-map compressed-nar-size compression))
+                     (eris-urns (filter-map compressed-eris-urn compression)))
                  (display (narinfo-string store item
                                           #:nar-path nar-path
                                           #:compressions compressions
-                                          #:file-sizes sizes)
+                                          #:file-sizes sizes
+                                          #:eris-urns eris-urns)
                           port)))
 
              ;; Make the cached narinfo world-readable, contrary to what
-- 
2.34.0