I won’t commit it yet because at this point the substituter caches only from one server, so users could populate /var/guix/substitute-binary/cache and lead other users to use the substituter that they chose (or to use nothing if the substituter server in question returned 404 for all the narinfos.) That should be easily fixed though (for the interested reader? ;-)). > --- /dev/null > +++ b/guix/scripts/publish.scm Make sure to add the license header. > + (display (_ "Usage: guix publish [OPTION]... > +Publish the store directory over HTTP.\n")) Maybe “Publish ~a over HTTP” with (%store-directory) would be more immediately obvious (and translations would be accurate ;-)). > +(define (load-derivation file-name) > + "Read the derivation located at FILE-NAME." > + (with-input-from-file file-name > + (lambda () > + (read-derivation (current-input-port))))) (call-with-input-file file read-derivation) > +(define (sign-string s) > + "Sign the hash of the string S with the daemon's key." > + (let ((hash (bytevector->hash-data (sha256 (string->utf8 s))))) > + (signature-sexp hash %private-key %public-key))) I had to change it to: (define (sign-string s) "Sign the hash of the string S with the daemon's key." (let ((hash (bytevector->hash-data (sha256 (string->utf8 s)) #:key-type (key-type %public-key)))) (signature-sexp hash %private-key %public-key))) Otherwise, ‘bytevector->hash-data’ will assume you have an ECC key and ‘sign’ will raise an exception if you happen to have an RSA key, for instance. Maybe ‘signed-string’ would be a more appropriate name since it’s a pure function. > +(define (narinfo-string store-path path-info derivation deriver key) Docstring please. I would suggest using keyword arguments for arguments above position 2. Aren’t ‘derivation’ and ‘deriver’ redundant with ‘path-info’? > + (let* ((url (string-append "nar/" (basename store-path))) > + (nar-hash (bytevector->base32-string > + (path-info-hash path-info))) > + (nar-size (path-info-nar-size path-info)) > + (references (string-join (map basename (path-info-refs path-info)) > + " ")) > + (system (derivation-system derivation)) > + (deriver (basename deriver)) > + (info (format #f Please align the RHS and maybe use single-word identifiers. (I hate it when I look this fussy.) > + (values '((content-type . (application/x-nix-archive > + (charset . "ISO-8859-1")))) Please add a comment saying that choosing ISO-8859-1 is crucial since otherwise HTTP clients will interpret the byte stream as UTF-8 and arbitrarily change invalid byte sequences. We don’t want anyone to feel that pain again. ;-) > + (format #t "Publishing store on port ~d~%" port) Lowercase and use (_ "publishing ..."), and add the file to po/guix/POTFILES.in. Now, it would be good to add a bunch of tests. :-) Perhaps one way to do it would be to write them in Scheme, and invoke ‘guix-publish’ in a thread, similar to the HTTP tests in tests/lint.scm. From there we could check .narinfo and .nar URLs. WDYT? Thanks for working on it in spite of the numerous issues you encountered! Ludo’.