publish: Make the nar URL prefix a parameter.

* guix/scripts/publish.scm (narinfo-string): Add #:nar-path and honor it.
(render-narinfo): Likewise.
(make-request-handler): Likewise.
(run-publish-server): Likewise.
* tests/publish.scm ("custom nar path"): New test.
master
Ludovic Courtès 2017-03-22 13:31:54 +01:00
parent 46f58390cb
commit cdd7a7d210
No known key found for this signature in database
GPG Key ID: 090B11993D9AEBB5
2 changed files with 64 additions and 20 deletions

View File

@ -204,16 +204,17 @@ compression disabled~%"))
(compose base64-encode string->utf8)) (compose base64-encode string->utf8))
(define* (narinfo-string store store-path key (define* (narinfo-string store store-path key
#:key (compression %no-compression)) #:key (compression %no-compression)
(nar-path "nar"))
"Generate a narinfo key/value string for STORE-PATH; an exception is raised "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 if STORE-PATH is invalid. Produce a URL that corresponds to COMPRESSION. The
narinfo is signed with KEY." narinfo is signed with KEY. NAR-PATH specifies the prefix for nar URLs."
(let* ((path-info (query-path-info store store-path)) (let* ((path-info (query-path-info store store-path))
(compression (if (compressed-file? store-path) (compression (if (compressed-file? store-path)
%no-compression %no-compression
compression)) compression))
(url (encode-and-join-uri-path (url (encode-and-join-uri-path
`("nar" `(,@(split-and-decode-uri-path nar-path)
,@(match compression ,@(match compression
(($ <compression> 'none) (($ <compression> 'none)
'()) '())
@ -275,11 +276,12 @@ References: ~a~%"
%nix-cache-info)))) %nix-cache-info))))
(define* (render-narinfo store request hash (define* (render-narinfo store request hash
#:key ttl (compression %no-compression)) #:key ttl (compression %no-compression)
(nar-path "nar"))
"Render metadata for the store path corresponding to HASH. If TTL is true, "Render metadata for the store path corresponding to HASH. If TTL is true,
advertise it as the maximum validity period (in seconds) via the advertise it as the maximum validity period (in seconds) via the
'Cache-Control' header. This allows 'guix substitute' to cache it for an 'Cache-Control' header. This allows 'guix substitute' to cache it for an
appropriate duration." appropriate duration. NAR-PATH specifies the prefix for nar URLs."
(let ((store-path (hash-part->path store hash))) (let ((store-path (hash-part->path store hash)))
(if (string-null? store-path) (if (string-null? store-path)
(not-found request) (not-found request)
@ -289,6 +291,7 @@ appropriate duration."
'())) '()))
(cut display (cut display
(narinfo-string store store-path (%private-key) (narinfo-string store store-path (%private-key)
#:nar-path nar-path
#:compression compression) #:compression compression)
<>))))) <>)))))
@ -478,7 +481,12 @@ blocking."
(define* (make-request-handler store (define* (make-request-handler store
#:key #:key
narinfo-ttl narinfo-ttl
(nar-path "nar")
(compression %no-compression)) (compression %no-compression))
(define nar-path?
(let ((expected (split-and-decode-uri-path nar-path)))
(cut equal? expected <>)))
(lambda (request body) (lambda (request body)
(format #t "~a ~a~%" (format #t "~a ~a~%"
(request-method request) (request-method request)
@ -494,19 +502,23 @@ blocking."
;; NARINFO-TTL. ;; NARINFO-TTL.
(render-narinfo store request hash (render-narinfo store request hash
#:ttl narinfo-ttl #:ttl narinfo-ttl
#:nar-path nar-path
#:compression compression)) #:compression compression))
;; /nar/file/NAME/sha256/HASH
(("file" name "sha256" hash)
(guard (c ((invalid-base32-character? c)
(not-found request)))
(let ((hash (nix-base32-string->bytevector hash)))
(render-content-addressed-file store request
name 'sha256 hash))))
;; Use different URLs depending on the compression type. This ;; Use different URLs depending on the compression type. This
;; guarantees that /nar URLs remain valid even when 'guix publish' ;; guarantees that /nar URLs remain valid even when 'guix publish'
;; is restarted with different compression parameters. ;; is restarted with different compression parameters.
;; /nar/<store-item>
(("nar" store-item)
(render-nar store request store-item
#:compression %no-compression))
;; /nar/gzip/<store-item> ;; /nar/gzip/<store-item>
(("nar" "gzip" store-item) ((components ... "gzip" store-item)
(if (zlib-available?) (if (and (nar-path? components) (zlib-available?))
(render-nar store request store-item (render-nar store request store-item
#:compression #:compression
(match compression (match compression
@ -516,19 +528,21 @@ blocking."
%default-gzip-compression))) %default-gzip-compression)))
(not-found request))) (not-found request)))
;; /nar/file/NAME/sha256/HASH ;; /nar/<store-item>
(("file" name "sha256" hash) ((components ... store-item)
(guard (c ((invalid-base32-character? c) (if (nar-path? components)
(render-nar store request store-item
#:compression %no-compression)
(not-found request))) (not-found request)))
(let ((hash (nix-base32-string->bytevector hash)))
(render-content-addressed-file store request (x (not-found request)))
name 'sha256 hash))))
(_ (not-found request)))
(not-found request)))) (not-found request))))
(define* (run-publish-server socket store (define* (run-publish-server socket store
#:key (compression %no-compression) narinfo-ttl) #:key (compression %no-compression)
(nar-path "nar") narinfo-ttl)
(run-server (make-request-handler store (run-server (make-request-handler store
#:nar-path nar-path
#:narinfo-ttl narinfo-ttl #:narinfo-ttl narinfo-ttl
#:compression compression) #:compression compression)
concurrent-http-server concurrent-http-server

View File

@ -232,6 +232,36 @@ References: ~%"
(list (assoc-ref info "Compression") (list (assoc-ref info "Compression")
(dirname (assoc-ref info "URL"))))) (dirname (assoc-ref info "URL")))))
(test-equal "custom nar path"
;; Serve nars at /foo/bar/chbouib instead of /nar.
(list `(("StorePath" . ,%item)
("URL" . ,(string-append "foo/bar/chbouib/" (basename %item)))
("Compression" . "none"))
200
404)
(let ((thread (with-separate-output-ports
(call-with-new-thread
(lambda ()
(guix-publish "--port=6798" "-C0"
"--nar-path=///foo/bar//chbouib/"))))))
(wait-until-ready 6798)
(let* ((base "http://localhost:6798/")
(part (store-path-hash-part %item))
(url (string-append base part ".narinfo"))
(nar-url (string-append base "foo/bar/chbouib/"
(basename %item)))
(body (http-get-port url)))
(list (filter (lambda (item)
(match item
(("Compression" . _) #t)
(("StorePath" . _) #t)
(("URL" . _) #t)
(_ #f)))
(recutils->alist body))
(response-code (http-get nar-url))
(response-code
(http-get (string-append base "nar/" (basename %item))))))))
(test-equal "/nar/ with properly encoded '+' sign" (test-equal "/nar/ with properly encoded '+' sign"
"Congrats!" "Congrats!"
(let ((item (add-text-to-store %store "fake-gtk+" "Congrats!"))) (let ((item (add-text-to-store %store "fake-gtk+" "Congrats!")))