publish: Add support for lzip.
* guix/scripts/publish.scm (show-help, %options): Support '-C METHOD' and '-C METHOD:LEVEL'. (default-compression): New procedure. (bake-narinfo+nar): Add lzip. (nar-response-port): Likewise. (string->compression-type): New procedure. (make-request-handler): Generalize /nar/gzip handler to handle /nar/lzip as well. * tests/publish.scm ("/nar/lzip/*"): New test. ("/*.narinfo with lzip compression"): New test. * doc/guix.texi (Invoking guix publish): Document it. (Requirements): Mention lzlib.
This commit is contained in:
parent
4e48923e75
commit
66229b04ae
|
@ -53,6 +53,8 @@
|
||||||
(eval . (put 'call-with-decompressed-port 'scheme-indent-function 2))
|
(eval . (put 'call-with-decompressed-port 'scheme-indent-function 2))
|
||||||
(eval . (put 'call-with-gzip-input-port 'scheme-indent-function 1))
|
(eval . (put 'call-with-gzip-input-port 'scheme-indent-function 1))
|
||||||
(eval . (put 'call-with-gzip-output-port 'scheme-indent-function 1))
|
(eval . (put 'call-with-gzip-output-port 'scheme-indent-function 1))
|
||||||
|
(eval . (put 'call-with-lzip-input-port 'scheme-indent-function 1))
|
||||||
|
(eval . (put 'call-with-lzip-output-port 'scheme-indent-function 1))
|
||||||
(eval . (put 'signature-case 'scheme-indent-function 1))
|
(eval . (put 'signature-case 'scheme-indent-function 1))
|
||||||
(eval . (put 'emacs-batch-eval 'scheme-indent-function 0))
|
(eval . (put 'emacs-batch-eval 'scheme-indent-function 0))
|
||||||
(eval . (put 'emacs-batch-edit-file 'scheme-indent-function 1))
|
(eval . (put 'emacs-batch-edit-file 'scheme-indent-function 1))
|
||||||
|
|
|
@ -757,6 +757,11 @@ Support for build offloading (@pxref{Daemon Offload Setup}) and
|
||||||
@uref{https://github.com/artyom-poptsov/guile-ssh, Guile-SSH},
|
@uref{https://github.com/artyom-poptsov/guile-ssh, Guile-SSH},
|
||||||
version 0.10.2 or later.
|
version 0.10.2 or later.
|
||||||
|
|
||||||
|
@item
|
||||||
|
When @url{https://www.nongnu.org/lzip/lzlib.html, lzlib} is available, lzlib
|
||||||
|
substitutes can be used and @command{guix publish} can compress substitutes
|
||||||
|
with lzlib.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
When @url{http://www.bzip.org, libbz2} is available,
|
When @url{http://www.bzip.org, libbz2} is available,
|
||||||
@command{guix-daemon} can use it to compress build logs.
|
@command{guix-daemon} can use it to compress build logs.
|
||||||
|
@ -9656,12 +9661,20 @@ accept connections from any interface.
|
||||||
Change privileges to @var{user} as soon as possible---i.e., once the
|
Change privileges to @var{user} as soon as possible---i.e., once the
|
||||||
server socket is open and the signing key has been read.
|
server socket is open and the signing key has been read.
|
||||||
|
|
||||||
@item --compression[=@var{level}]
|
@item --compression[=@var{method}[:@var{level}]]
|
||||||
@itemx -C [@var{level}]
|
@itemx -C [@var{method}[:@var{level}]]
|
||||||
Compress data using the given @var{level}. When @var{level} is zero,
|
Compress data using the given @var{method} and @var{level}. @var{method} is
|
||||||
disable compression. The range 1 to 9 corresponds to different gzip
|
one of @code{lzip} and @code{gzip}; when @var{method} is omitted, @code{gzip}
|
||||||
compression levels: 1 is the fastest, and 9 is the best (CPU-intensive).
|
is used.
|
||||||
The default is 3.
|
|
||||||
|
When @var{level} is zero, disable compression. The range 1 to 9 corresponds
|
||||||
|
to different compression levels: 1 is the fastest, and 9 is the best
|
||||||
|
(CPU-intensive). The default is 3.
|
||||||
|
|
||||||
|
Usually, @code{lzip} compresses noticeably better than @code{gzip} for a small
|
||||||
|
increase in CPU usage; see
|
||||||
|
@uref{https://nongnu.org/lzip/lzip_benchmark.html,benchmarks on the lzip Web
|
||||||
|
page}.
|
||||||
|
|
||||||
Unless @option{--cache} is used, compression occurs on the fly and
|
Unless @option{--cache} is used, compression occurs on the fly and
|
||||||
the compressed streams are not
|
the compressed streams are not
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
;;; GNU Guix --- Functional package management for GNU
|
;;; GNU Guix --- Functional package management for GNU
|
||||||
;;; Copyright © 2015 David Thompson <davet@gnu.org>
|
;;; Copyright © 2015 David Thompson <davet@gnu.org>
|
||||||
;;; Copyright © 2015, 2016, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
|
;;; Copyright © 2015, 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
|
||||||
;;;
|
;;;
|
||||||
;;; This file is part of GNU Guix.
|
;;; This file is part of GNU Guix.
|
||||||
;;;
|
;;;
|
||||||
|
@ -51,6 +51,7 @@
|
||||||
#:use-module (guix store)
|
#:use-module (guix store)
|
||||||
#:use-module ((guix serialization) #:select (write-file))
|
#:use-module ((guix serialization) #:select (write-file))
|
||||||
#:use-module (guix zlib)
|
#:use-module (guix zlib)
|
||||||
|
#:autoload (guix lzlib) (lzlib-available?)
|
||||||
#:use-module (guix cache)
|
#:use-module (guix cache)
|
||||||
#:use-module (guix ui)
|
#:use-module (guix ui)
|
||||||
#:use-module (guix scripts)
|
#:use-module (guix scripts)
|
||||||
|
@ -74,8 +75,8 @@ Publish ~a over HTTP.\n") %store-directory)
|
||||||
(display (G_ "
|
(display (G_ "
|
||||||
-u, --user=USER change privileges to USER as soon as possible"))
|
-u, --user=USER change privileges to USER as soon as possible"))
|
||||||
(display (G_ "
|
(display (G_ "
|
||||||
-C, --compression[=LEVEL]
|
-C, --compression[=METHOD:LEVEL]
|
||||||
compress archives at LEVEL"))
|
compress archives with METHOD at LEVEL"))
|
||||||
(display (G_ "
|
(display (G_ "
|
||||||
-c, --cache=DIRECTORY cache published items to DIRECTORY"))
|
-c, --cache=DIRECTORY cache published items to DIRECTORY"))
|
||||||
(display (G_ "
|
(display (G_ "
|
||||||
|
@ -121,6 +122,9 @@ Publish ~a over HTTP.\n") %store-directory)
|
||||||
;; Since we compress on the fly, default to fast compression.
|
;; Since we compress on the fly, default to fast compression.
|
||||||
(compression 'gzip 3))
|
(compression 'gzip 3))
|
||||||
|
|
||||||
|
(define (default-compression type)
|
||||||
|
(compression type 3))
|
||||||
|
|
||||||
(define (actual-compression item requested)
|
(define (actual-compression item requested)
|
||||||
"Return the actual compression used for ITEM, which may be %NO-COMPRESSION
|
"Return the actual compression used for ITEM, which may be %NO-COMPRESSION
|
||||||
if ITEM is already compressed."
|
if ITEM is already compressed."
|
||||||
|
@ -153,18 +157,28 @@ if ITEM is already compressed."
|
||||||
name)))))
|
name)))))
|
||||||
(option '(#\C "compression") #f #t
|
(option '(#\C "compression") #f #t
|
||||||
(lambda (opt name arg result)
|
(lambda (opt name arg result)
|
||||||
(match (if arg (string->number* arg) 3)
|
(let* ((colon (string-index arg #\:))
|
||||||
|
(type (cond
|
||||||
|
(colon (string-take arg colon))
|
||||||
|
((string->number arg) "gzip")
|
||||||
|
(else arg)))
|
||||||
|
(level (if colon
|
||||||
|
(string->number*
|
||||||
|
(string-drop arg (+ 1 colon)))
|
||||||
|
(or (string->number arg) 3))))
|
||||||
|
(match level
|
||||||
(0
|
(0
|
||||||
(alist-cons 'compression %no-compression result))
|
(alist-cons 'compression %no-compression result))
|
||||||
(level
|
(level
|
||||||
(if (zlib-available?)
|
(match (string->compression-type type)
|
||||||
|
((? symbol? type)
|
||||||
(alist-cons 'compression
|
(alist-cons 'compression
|
||||||
(compression 'gzip level)
|
(compression type level)
|
||||||
result)
|
result))
|
||||||
(begin
|
(_
|
||||||
(warning (G_ "zlib support is missing; \
|
(warning (G_ "~a: unsupported compression type~%")
|
||||||
compression disabled~%"))
|
type)
|
||||||
result))))))
|
result)))))))
|
||||||
(option '(#\c "cache") #t #f
|
(option '(#\c "cache") #t #f
|
||||||
(lambda (opt name arg result)
|
(lambda (opt name arg result)
|
||||||
(alist-cons 'cache arg result)))
|
(alist-cons 'cache arg result)))
|
||||||
|
@ -511,6 +525,13 @@ requested using POOL."
|
||||||
#:level (compression-level compression)
|
#:level (compression-level compression)
|
||||||
#:buffer-size (* 128 1024))
|
#:buffer-size (* 128 1024))
|
||||||
(rename-file (string-append nar ".tmp") nar))
|
(rename-file (string-append nar ".tmp") nar))
|
||||||
|
('lzip
|
||||||
|
;; Note: the file port gets closed along with the lzip port.
|
||||||
|
(call-with-lzip-output-port (open-output-file (string-append nar ".tmp"))
|
||||||
|
(lambda (port)
|
||||||
|
(write-file item port))
|
||||||
|
#:level (compression-level compression))
|
||||||
|
(rename-file (string-append nar ".tmp") nar))
|
||||||
('none
|
('none
|
||||||
;; Cache nars even when compression is disabled so that we can
|
;; Cache nars even when compression is disabled so that we can
|
||||||
;; guarantee the TTL (see <https://bugs.gnu.org/28664>.)
|
;; guarantee the TTL (see <https://bugs.gnu.org/28664>.)
|
||||||
|
@ -715,6 +736,9 @@ example: \"/foo/bar\" yields '(\"foo\" \"bar\")."
|
||||||
(make-gzip-output-port (response-port response)
|
(make-gzip-output-port (response-port response)
|
||||||
#:level level
|
#:level level
|
||||||
#:buffer-size (* 64 1024)))
|
#:buffer-size (* 64 1024)))
|
||||||
|
(($ <compression> 'lzip level)
|
||||||
|
(make-lzip-output-port (response-port response)
|
||||||
|
#:level level))
|
||||||
(($ <compression> 'none)
|
(($ <compression> 'none)
|
||||||
(response-port response))
|
(response-port response))
|
||||||
(#f
|
(#f
|
||||||
|
@ -789,12 +813,23 @@ blocking."
|
||||||
http-write
|
http-write
|
||||||
(@@ (web server http) http-close))
|
(@@ (web server http) http-close))
|
||||||
|
|
||||||
|
(define (string->compression-type string)
|
||||||
|
"Return a symbol denoting the compression method expressed by STRING; return
|
||||||
|
#f if STRING doesn't match any supported method."
|
||||||
|
(match string
|
||||||
|
("gzip" (and (zlib-available?) 'gzip))
|
||||||
|
("lzip" (and (lzlib-available?) 'lzip))
|
||||||
|
(_ #f)))
|
||||||
|
|
||||||
(define* (make-request-handler store
|
(define* (make-request-handler store
|
||||||
#:key
|
#:key
|
||||||
cache pool
|
cache pool
|
||||||
narinfo-ttl
|
narinfo-ttl
|
||||||
(nar-path "nar")
|
(nar-path "nar")
|
||||||
(compression %no-compression))
|
(compression %no-compression))
|
||||||
|
(define compression-type?
|
||||||
|
string->compression-type)
|
||||||
|
|
||||||
(define nar-path?
|
(define nar-path?
|
||||||
(let ((expected (split-and-decode-uri-path nar-path)))
|
(let ((expected (split-and-decode-uri-path nar-path)))
|
||||||
(cut equal? expected <>)))
|
(cut equal? expected <>)))
|
||||||
|
@ -843,13 +878,18 @@ blocking."
|
||||||
;; is restarted with different compression parameters.
|
;; is restarted with different compression parameters.
|
||||||
|
|
||||||
;; /nar/gzip/<store-item>
|
;; /nar/gzip/<store-item>
|
||||||
((components ... "gzip" store-item)
|
((components ... (? compression-type? type) store-item)
|
||||||
(if (and (nar-path? components) (zlib-available?))
|
(if (nar-path? components)
|
||||||
(let ((compression (match compression
|
(let* ((compression-type (string->compression-type type))
|
||||||
(($ <compression> 'gzip)
|
(compression (match compression
|
||||||
compression)
|
(($ <compression> type)
|
||||||
|
(if (eq? type compression-type)
|
||||||
|
compression
|
||||||
|
(default-compression
|
||||||
|
compression-type)))
|
||||||
(_
|
(_
|
||||||
%default-gzip-compression))))
|
(default-compression
|
||||||
|
compression-type)))))
|
||||||
(if cache
|
(if cache
|
||||||
(render-nar/cached store cache request store-item
|
(render-nar/cached store cache request store-item
|
||||||
#:ttl narinfo-ttl
|
#:ttl narinfo-ttl
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#:use-module (gcrypt pk-crypto)
|
#:use-module (gcrypt pk-crypto)
|
||||||
#:use-module ((guix pki) #:select (%public-key-file %private-key-file))
|
#:use-module ((guix pki) #:select (%public-key-file %private-key-file))
|
||||||
#:use-module (guix zlib)
|
#:use-module (guix zlib)
|
||||||
|
#:use-module (guix lzlib)
|
||||||
#:use-module (web uri)
|
#:use-module (web uri)
|
||||||
#:use-module (web client)
|
#:use-module (web client)
|
||||||
#:use-module (web response)
|
#:use-module (web response)
|
||||||
|
@ -229,6 +230,19 @@ FileSize: ~a~%"
|
||||||
(string-append "/nar/gzip/" (basename %item))))))
|
(string-append "/nar/gzip/" (basename %item))))))
|
||||||
(get-bytevector-n nar (bytevector-length %gzip-magic-bytes))))
|
(get-bytevector-n nar (bytevector-length %gzip-magic-bytes))))
|
||||||
|
|
||||||
|
(unless (lzlib-available?)
|
||||||
|
(test-skip 1))
|
||||||
|
(test-equal "/nar/lzip/*"
|
||||||
|
"bar"
|
||||||
|
(call-with-temporary-output-file
|
||||||
|
(lambda (temp port)
|
||||||
|
(let ((nar (http-get-port
|
||||||
|
(publish-uri
|
||||||
|
(string-append "/nar/lzip/" (basename %item))))))
|
||||||
|
(call-with-lzip-input-port nar
|
||||||
|
(cut restore-file <> temp)))
|
||||||
|
(call-with-input-file temp read-string))))
|
||||||
|
|
||||||
(unless (zlib-available?)
|
(unless (zlib-available?)
|
||||||
(test-skip 1))
|
(test-skip 1))
|
||||||
(test-equal "/*.narinfo with compression"
|
(test-equal "/*.narinfo with compression"
|
||||||
|
@ -251,6 +265,28 @@ FileSize: ~a~%"
|
||||||
(_ #f)))
|
(_ #f)))
|
||||||
(recutils->alist body)))))
|
(recutils->alist body)))))
|
||||||
|
|
||||||
|
(unless (lzlib-available?)
|
||||||
|
(test-skip 1))
|
||||||
|
(test-equal "/*.narinfo with lzip compression"
|
||||||
|
`(("StorePath" . ,%item)
|
||||||
|
("URL" . ,(string-append "nar/lzip/" (basename %item)))
|
||||||
|
("Compression" . "lzip"))
|
||||||
|
(let ((thread (with-separate-output-ports
|
||||||
|
(call-with-new-thread
|
||||||
|
(lambda ()
|
||||||
|
(guix-publish "--port=6790" "-Clzip"))))))
|
||||||
|
(wait-until-ready 6790)
|
||||||
|
(let* ((url (string-append "http://localhost:6790/"
|
||||||
|
(store-path-hash-part %item) ".narinfo"))
|
||||||
|
(body (http-get-port url)))
|
||||||
|
(filter (lambda (item)
|
||||||
|
(match item
|
||||||
|
(("Compression" . _) #t)
|
||||||
|
(("StorePath" . _) #t)
|
||||||
|
(("URL" . _) #t)
|
||||||
|
(_ #f)))
|
||||||
|
(recutils->alist body)))))
|
||||||
|
|
||||||
(unless (zlib-available?)
|
(unless (zlib-available?)
|
||||||
(test-skip 1))
|
(test-skip 1))
|
||||||
(test-equal "/*.narinfo for a compressed file"
|
(test-equal "/*.narinfo for a compressed file"
|
||||||
|
|
Loading…
Reference in New Issue