summaryrefslogtreecommitdiff
path: root/guix
diff options
context:
space:
mode:
Diffstat (limited to 'guix')
-rw-r--r--guix/cache.scm9
-rw-r--r--guix/git.scm44
-rw-r--r--guix/import/cpan.scm3
-rw-r--r--guix/import/cran.scm8
-rw-r--r--guix/import/gem.scm5
-rw-r--r--guix/import/texlive.scm28
-rw-r--r--guix/licenses.scm10
-rw-r--r--guix/modules.scm4
-rw-r--r--guix/narinfo.scm326
-rw-r--r--guix/packages.scm38
-rw-r--r--guix/repl.scm8
-rw-r--r--guix/scripts/archive.scm4
-rw-r--r--guix/scripts/challenge.scm1
-rw-r--r--guix/scripts/environment.scm2
-rw-r--r--guix/scripts/publish.scm31
-rwxr-xr-xguix/scripts/substitute.scm298
-rw-r--r--guix/scripts/system.scm23
-rw-r--r--guix/scripts/weather.scm1
-rw-r--r--guix/self.scm6
-rw-r--r--guix/serialization.scm16
-rw-r--r--guix/store.scm17
-rw-r--r--guix/swh.scm3
-rw-r--r--guix/transformations.scm49
-rw-r--r--guix/upstream.scm28
-rw-r--r--guix/utils.scm23
25 files changed, 601 insertions, 384 deletions
diff --git a/guix/cache.scm b/guix/cache.scm
index feff131068..0401a9d428 100644
--- a/guix/cache.scm
+++ b/guix/cache.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -47,13 +47,14 @@
(unless (= ENOENT (system-error-errno args))
(apply throw args)))))
-(define (file-expiration-time ttl)
+(define* (file-expiration-time ttl #:optional (timestamp stat:atime))
"Return a procedure that, when passed a file, returns its \"expiration
-time\" computed as its last-access time + TTL seconds."
+time\" computed as its timestamp + TTL seconds. Call TIMESTAMP to obtain the
+relevant timestamp from the result of 'stat'."
(lambda (file)
(match (stat file #f)
(#f 0) ;FILE may have been deleted in the meantime
- (st (+ (stat:atime st) ttl)))))
+ (st (+ (timestamp st) ttl)))))
(define* (remove-expired-cache-entries entries
#:key
diff --git a/guix/git.scm b/guix/git.scm
index ca77b9f54b..a5103547d3 100644
--- a/guix/git.scm
+++ b/guix/git.scm
@@ -1,6 +1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2017, 2020 Mathieu Othacehe <m.othacehe@gmail.com>
-;;; Copyright © 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -23,8 +23,10 @@
#:use-module (git submodule)
#:use-module (guix i18n)
#:use-module (guix base32)
+ #:use-module (guix cache)
#:use-module (gcrypt hash)
- #:use-module ((guix build utils) #:select (mkdir-p))
+ #:use-module ((guix build utils)
+ #:select (mkdir-p delete-file-recursively))
#:use-module (guix store)
#:use-module (guix utils)
#:use-module (guix records)
@@ -35,6 +37,7 @@
#:use-module (rnrs bytevectors)
#:use-module (ice-9 format)
#:use-module (ice-9 match)
+ #:use-module (ice-9 ftw)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-11)
#:use-module (srfi srfi-34)
@@ -318,6 +321,24 @@ definitely available in REPOSITORY, false otherwise."
(_
#f)))
+(define cached-checkout-expiration
+ ;; Return the expiration time procedure for a cached checkout.
+ ;; TODO: Honor $GUIX_GIT_CACHE_EXPIRATION.
+
+ ;; Use the mtime rather than the atime to cope with file systems mounted
+ ;; with 'noatime'.
+ (file-expiration-time (* 90 24 3600) stat:mtime))
+
+(define %checkout-cache-cleanup-period
+ ;; Period for the removal of expired cached checkouts.
+ (* 5 24 3600))
+
+(define (delete-checkout directory)
+ "Delete DIRECTORY recursively, in an atomic fashion."
+ (let ((trashed (string-append directory ".trashed")))
+ (rename-file directory trashed)
+ (delete-file-recursively trashed)))
+
(define* (update-cached-checkout url
#:key
(ref '(branch . "master"))
@@ -341,6 +362,14 @@ When RECURSIVE? is true, check out submodules as well, if any.
When CHECK-OUT? is true, reset the cached working tree to REF; otherwise leave
it unchanged."
+ (define (cache-entries directory)
+ (filter-map (match-lambda
+ ((or "." "..")
+ #f)
+ (file
+ (string-append directory "/" file)))
+ (or (scandir directory) '())))
+
(define canonical-ref
;; We used to require callers to specify "origin/" for each branch, which
;; made little sense since the cache should be transparent to them. So
@@ -387,6 +416,17 @@ it unchanged."
;; REPOSITORY as soon as possible.
(repository-close! repository)
+ ;; When CACHE-DIRECTORY is a sub-directory of the default cache
+ ;; directory, remove expired checkouts that are next to it.
+ (let ((parent (dirname cache-directory)))
+ (when (string=? parent (%repository-cache-directory))
+ (maybe-remove-expired-cache-entries parent cache-entries
+ #:entry-expiration
+ cached-checkout-expiration
+ #:delete-entry delete-checkout
+ #:cleanup-period
+ %checkout-cache-cleanup-period)))
+
(values cache-directory (oid->string oid) relation)))))
(define* (latest-repository-commit store url
diff --git a/guix/import/cpan.scm b/guix/import/cpan.scm
index 514417f781..87abe9c2f1 100644
--- a/guix/import/cpan.scm
+++ b/guix/import/cpan.scm
@@ -3,7 +3,7 @@
;;; Copyright © 2015 Mark H Weaver <mhw@netris.org>
;;; Copyright © 2016 Alex Sassmannshausen <alex@pompo.co>
;;; Copyright © 2017, 2018 Tobias Geerinckx-Rice <me@tobias.gr>
-;;; Copyright © 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -109,6 +109,7 @@
(home-page cpan-release-home-page "resources"
(match-lambda
(#f #f)
+ ((? unspecified?) #f)
((lst ...) (assoc-ref lst "homepage"))))
(dependencies cpan-release-dependencies "dependency"
(lambda (vector)
diff --git a/guix/import/cran.scm b/guix/import/cran.scm
index fd44d80915..e8caf080fd 100644
--- a/guix/import/cran.scm
+++ b/guix/import/cran.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2015, 2016, 2017, 2018, 2019, 2020 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2015, 2016, 2017, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2020 Martin Becze <mjbecze@riseup.net>
@@ -341,7 +341,11 @@ empty list when the FIELD cannot be found."
;; The field for system dependencies is often abused to specify non-package
;; dependencies (such as c++11). This list is used to ignore them.
(define invalid-packages
- (list "c++11"))
+ (list "c++11"
+ "c++14"
+ "linux"
+ "getopt::long"
+ "xquartz"))
(define cran-guix-name (cut guix-name "r-" <>))
diff --git a/guix/import/gem.scm b/guix/import/gem.scm
index 1f6f94532e..418d716be6 100644
--- a/guix/import/gem.scm
+++ b/guix/import/gem.scm
@@ -2,7 +2,7 @@
;;; Copyright © 2015 David Thompson <davet@gnu.org>
;;; Copyright © 2016 Ben Woodcroft <donttrustben@gmail.com>
;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
-;;; Copyright © 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2020 Martin Becze <mjbecze@riseup.net>
;;;
;;; This file is part of GNU Guix.
@@ -49,6 +49,7 @@
;; This is sometimes #nil (the JSON 'null' value). Arrange
;; to always return a list.
(cond ((not licenses) '())
+ ((unspecified? licenses) '())
((vector? licenses) (vector->list licenses))
(else '()))))
(info gem-info)
@@ -69,7 +70,7 @@
json->gem-dependency-list))
(define (json->gem-dependency-list vector)
- (if vector
+ (if (and vector (not (unspecified? vector)))
(map json->gem-dependency (vector->list vector))
'()))
diff --git a/guix/import/texlive.scm b/guix/import/texlive.scm
index a84683ef6f..18d8b95ee0 100644
--- a/guix/import/texlive.scm
+++ b/guix/import/texlive.scm
@@ -1,5 +1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2017 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -25,6 +26,8 @@
#:use-module (srfi srfi-26)
#:use-module (srfi srfi-34)
#:use-module (web uri)
+ #:use-module (guix diagnostics)
+ #:use-module (guix i18n)
#:use-module (guix http-client)
#:use-module (gcrypt hash)
#:use-module (guix memoization)
@@ -149,19 +152,24 @@ expression describing it."
(home-page (string-append "http://www.ctan.org/pkg/" id))
(ref (texlive-ref component id))
(checkout (download-svn-to-store store ref)))
+ (unless checkout
+ (warning (G_ "Could not determine source location. \
+Please manually specify the source field.~%")))
`(package
(name ,(guix-name component id))
(version ,version)
- (source (origin
- (method svn-fetch)
- (uri (texlive-ref ,component ,id))
- (sha256
- (base32
- ,(bytevector->nix-base32-string
- (let-values (((port get-hash) (open-sha256-port)))
- (write-file checkout port)
- (force-output port)
- (get-hash)))))))
+ (source ,(if checkout
+ `(origin
+ (method svn-fetch)
+ (uri (texlive-ref ,component ,id))
+ (sha256
+ (base32
+ ,(bytevector->nix-base32-string
+ (let-values (((port get-hash) (open-sha256-port)))
+ (write-file checkout port)
+ (force-output port)
+ (get-hash))))))
+ #f))
(build-system texlive-build-system)
(arguments ,`(,'quote (#:tex-directory ,(string-join (list component id) "/"))))
(home-page ,home-page)
diff --git a/guix/licenses.scm b/guix/licenses.scm
index 255b755e6c..63010a7231 100644
--- a/guix/licenses.scm
+++ b/guix/licenses.scm
@@ -78,7 +78,7 @@
mpl1.0 mpl1.1 mpl2.0
ms-pl
ncsa
- npsl
+ nmap
ogl-psi1.0
openldap2.8 openssl
perl-license
@@ -531,10 +531,10 @@ at URI, which may be a file:// URI pointing the package's tree."
"http://directory.fsf.org/wiki/License:IllinoisNCSA"
"https://www.gnu.org/licenses/license-list#NCSA"))
-(define npsl
- (license "Nmap Public Source License"
- "https://svn.nmap.org/nmap/LICENSE"
- "https://nmap.org/npsl/"))
+(define nmap
+ (license "Nmap license"
+ "https://svn.nmap.org/nmap/COPYING"
+ "https://fedoraproject.org/wiki/Licensing/Nmap"))
(define ogl-psi1.0
(license "Open Government Licence for Public Sector Information"
diff --git a/guix/modules.scm b/guix/modules.scm
index 1a6fafe35b..61bc8e1978 100644
--- a/guix/modules.scm
+++ b/guix/modules.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2016, 2017, 2018, 2019, 2021 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -77,7 +77,7 @@ CLAUSES."
((#:autoload module _ rest ...)
(loop rest (cons module result)))
(((or #:export #:re-export #:export-syntax #:re-export-syntax
- #:replace #:version)
+ #:re-export-and-replace #:replace #:version)
_ rest ...)
(loop rest result))
(((or #:pure #:no-backtrace) rest ...)
diff --git a/guix/narinfo.scm b/guix/narinfo.scm
new file mode 100644
index 0000000000..241090ec98
--- /dev/null
+++ b/guix/narinfo.scm
@@ -0,0 +1,326 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2014 Nikita Karetnikov <nikita@karetnikov.org>
+;;; Copyright © 2018 Kyle Meyer <kyle@kyleam.com>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix narinfo)
+ #:use-module (guix pki)
+ #:use-module (guix i18n)
+ #:use-module (guix base32)
+ #:use-module (guix base64)
+ #:use-module (guix records)
+ #:use-module (guix diagnostics)
+ #:use-module (guix scripts substitute)
+ #:use-module (gcrypt hash)
+ #:use-module (gcrypt pk-crypto)
+ #:use-module (rnrs bytevectors)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-9)
+ #:use-module (srfi srfi-26)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 binary-ports)
+ #:use-module (web uri)
+ #:export (narinfo-signature->canonical-sexp
+
+ narinfo?
+ narinfo-path
+ narinfo-uris
+ narinfo-uri-base
+ narinfo-compressions
+ narinfo-file-hashes
+ narinfo-file-sizes
+ narinfo-hash
+ narinfo-size
+ narinfo-references
+ narinfo-deriver
+ narinfo-system
+ narinfo-signature
+
+ narinfo-hash-algorithm+value
+
+ narinfo-hash->sha256
+ narinfo-best-uri
+
+ valid-narinfo?
+
+ read-narinfo
+ write-narinfo
+
+ string->narinfo
+ narinfo->string
+
+ equivalent-narinfo?))
+
+(define-record-type <narinfo>
+ (%make-narinfo path uri-base uris 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
+ (compressions narinfo-compressions) ;list of strings
+ (file-sizes narinfo-file-sizes) ;list of (integers | #f)
+ (file-hashes narinfo-file-hashes)
+ (nar-hash narinfo-hash)
+ (nar-size narinfo-size)
+ (references narinfo-references)
+ (deriver narinfo-deriver)
+ (system narinfo-system)
+ (signature narinfo-signature) ; canonical sexp
+ ;; The original contents of a narinfo file. This field is needed because we
+ ;; want to preserve the exact textual representation for verification purposes.
+ ;; See <https://lists.gnu.org/archive/html/guix-devel/2014-02/msg00340.html>
+ ;; for more information.
+ (contents narinfo-contents))
+
+(define (narinfo-hash-algorithm+value narinfo)
+ "Return two values: the hash algorithm used by NARINFO and its value as a
+bytevector."
+ (match (string-tokenize (narinfo-hash narinfo)
+ (char-set-complement (char-set #\:)))
+ ((algorithm base32)
+ (values (lookup-hash-algorithm (string->symbol algorithm))
+ (nix-base32-string->bytevector base32)))
+ (_
+ (raise (formatted-message
+ (G_ "invalid narinfo hash: ~s") (narinfo-hash narinfo))))))
+
+(define (narinfo-hash->sha256 hash)
+ "If the string HASH denotes a sha256 hash, return it as a bytevector.
+Otherwise return #f."
+ (and (string-prefix? "sha256:" hash)
+ (nix-base32-string->bytevector (string-drop hash 7))))
+
+(define (narinfo-signature->canonical-sexp str)
+ "Return the value of a narinfo's 'Signature' field as a canonical sexp."
+ (match (string-split str #\;)
+ ((version host-name sig)
+ (let ((maybe-number (string->number version)))
+ (cond ((not (number? maybe-number))
+ (leave (G_ "signature version must be a number: ~s~%")
+ version))
+ ;; Currently, there are no other versions.
+ ((not (= 1 maybe-number))
+ (leave (G_ "unsupported signature version: ~a~%")
+ maybe-number))
+ (else
+ (let ((signature (utf8->string (base64-decode sig))))
+ (catch 'gcry-error
+ (lambda ()
+ (string->canonical-sexp signature))
+ (lambda (key proc err)
+ (leave (G_ "signature is not a valid \
+s-expression: ~s~%")
+ signature))))))))
+ (x
+ (leave (G_ "invalid format of the signature field: ~a~%") x))))
+
+(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
+ nar-hash nar-size references deriver system
+ signature)
+ "Return a new <narinfo> object."
+ (define len (length urls))
+ (%make-narinfo path cache-url
+ ;; Handle the case where URL is a relative URL.
+ (map (lambda (url)
+ (or (string->uri url)
+ (string->uri
+ (string-append cache-url "/" url))))
+ urls)
+ compressions
+ (match file-sizes
+ (() (make-list len #f))
+ ((lst ...) (map string->number lst)))
+ (match file-hashes
+ (() (make-list len #f))
+ ((lst ...) (map string->number lst)))
+ nar-hash
+ (and=> nar-size string->number)
+ (string-tokenize references)
+ (match deriver
+ ((or #f "") #f)
+ (_ deriver))
+ system
+ (false-if-exception
+ (and=> signature narinfo-signature->canonical-sexp))
+ str)))
+
+(define fields->alist
+ ;; The narinfo format is really just like recutils.
+ recutils->alist)
+
+(define* (read-narinfo port #:optional url
+ #:key size)
+ "Read a narinfo from PORT. If URL is true, it must be a string used to
+build full URIs from relative URIs found while reading PORT. When SIZE is
+true, read at most SIZE bytes from PORT; otherwise, read as much as possible.
+
+No authentication and authorization checks are performed here!"
+ (let ((str (utf8->string (if size
+ (get-bytevector-n port size)
+ (get-bytevector-all port)))))
+ (alist->record (call-with-input-string str fields->alist)
+ (narinfo-maker str url)
+ '("StorePath" "URL" "Compression"
+ "FileHash" "FileSize" "NarHash" "NarSize"
+ "References" "Deriver" "System"
+ "Signature")
+ '("URL" "Compression" "FileSize" "FileHash"))))
+
+(define (narinfo-sha256 narinfo)
+ "Return the sha256 hash of NARINFO as a bytevector, or #f if NARINFO lacks a
+'Signature' field."
+ (define %mandatory-fields
+ ;; List of fields that must be signed. If they are not signed, the
+ ;; narinfo is considered unsigned.
+ '("StorePath" "NarHash" "References"))
+
+ (let ((contents (narinfo-contents narinfo)))
+ (match (string-contains contents "Signature:")
+ (#f #f)
+ (index
+ (let* ((above-signature (string-take contents index))
+ (signed-fields (match (call-with-input-string above-signature
+ fields->alist)
+ (((fields . values) ...) fields))))
+ (and (every (cut member <> signed-fields) %mandatory-fields)
+ (sha256 (string->utf8 above-signature))))))))
+
+(define* (valid-narinfo? narinfo #:optional (acl (current-acl))
+ #:key verbose?)
+ "Return #t if NARINFO's signature is not valid."
+ (let ((hash (narinfo-sha256 narinfo))
+ (signature (narinfo-signature narinfo))
+ (uri (uri->string (first (narinfo-uris narinfo)))))
+ (and hash signature
+ (signature-case (signature hash acl)
+ (valid-signature #t)
+ (invalid-signature
+ (when verbose?
+ (format (current-error-port)
+ "invalid signature for substitute at '~a'~%"
+ uri))
+ #f)
+ (hash-mismatch
+ (when verbose?
+ (format (current-error-port)
+ "hash mismatch for substitute at '~a'~%"
+ uri))
+ #f)
+ (unauthorized-key
+ (when verbose?
+ (format (current-error-port)
+ "substitute at '~a' is signed by an \
+unauthorized party~%"
+ uri))
+ #f)
+ (corrupt-signature
+ (when verbose?
+ (format (current-error-port)
+ "corrupt signature for substitute at '~a'~%"
+ uri))
+ #f)))))
+
+(define (write-narinfo narinfo port)
+ "Write NARINFO to PORT."
+ (put-bytevector port (string->utf8 (narinfo-contents narinfo))))
+
+(define (narinfo->string narinfo)
+ "Return the external representation of NARINFO."
+ (call-with-output-string (cut write-narinfo narinfo <>)))
+
+(define (string->narinfo str cache-uri)
+ "Return the narinfo represented by STR. Assume CACHE-URI as the base URI of
+the cache STR originates form."
+ (call-with-input-string str (cut read-narinfo <> cache-uri)))
+
+(define (equivalent-narinfo? narinfo1 narinfo2)
+ "Return true if NARINFO1 and NARINFO2 are equivalent--i.e., if they describe
+the same store item. This ignores unnecessary metadata such as the Nar URL."
+ (and (string=? (narinfo-hash narinfo1)
+ (narinfo-hash narinfo2))
+
+ ;; The following is not needed if all we want is to download a valid
+ ;; nar, but it's necessary if we want valid narinfo.
+ (string=? (narinfo-path narinfo1)
+ (narinfo-path narinfo2))
+ (equal? (narinfo-references narinfo1)
+ (narinfo-references narinfo2))
+
+ (= (narinfo-size narinfo1)
+ (narinfo-size narinfo2))))
+
+(define %compression-methods
+ ;; Known compression methods and a thunk to determine whether they're
+ ;; supported. See 'decompressed-port' in (guix utils).
+ `(("gzip" . ,(const #t))
+ ("lzip" . ,(const #t))
+ ("zstd" . ,(lambda ()
+ (resolve-module '(zstd) #t #f #:ensure #f)))
+ ("xz" . ,(const #t))
+ ("bzip2" . ,(const #t))
+ ("none" . ,(const #t))))
+
+(define (supported-compression? compression)
+ "Return true if COMPRESSION, a string, denotes a supported compression
+method."
+ (match (assoc-ref %compression-methods compression)
+ (#f #f)
+ (supported? (supported?))))
+
+(define (compresses-better? compression1 compression2)
+ "Return true if COMPRESSION1 generally compresses better than COMPRESSION2;
+this is a rough approximation."
+ (match compression1
+ ("none" #f)
+ ("gzip" (string=? compression2 "none"))
+ ("lzip" #t)
+ (_ (or (string=? compression2 "none")
+ (string=? compression2 "gzip")))))
+
+(define (narinfo-best-uri narinfo)
+ "Select the \"best\" URI to download NARINFO's nar, and return three values:
+the URI, its compression method (a string), and the compressed file size."
+ (define choices
+ (filter (match-lambda
+ ((uri compression file-size)
+ (supported-compression? compression)))
+ (zip (narinfo-uris narinfo)
+ (narinfo-compressions narinfo)
+ (narinfo-file-sizes narinfo))))
+
+ (define (file-size<? c1 c2)
+ (match c1
+ ((uri1 compression1 (? integer? file-size1))
+ (match c2
+ ((uri2 compression2 (? integer? file-size2))
+ (< file-size1 file-size2))
+ (_ #t)))
+ ((uri compression1 #f)
+ (match c2
+ ((uri2 compression2 _)
+ (compresses-better? compression1 compression2))))
+ (_ #f))) ;we can't tell
+
+ (match (sort choices file-size<?)
+ (((uri compression file-size) _ ...)
+ (values uri compression file-size))))
diff --git a/guix/packages.scm b/guix/packages.scm
index 6fa761f569..9305dabcec 100644
--- a/guix/packages.scm
+++ b/guix/packages.scm
@@ -167,6 +167,25 @@
;;;
;;; Code:
+(define-syntax-rule (define-compile-time-decoder name string->bytevector)
+ "Define NAME as a macro that runs STRING->BYTEVECTOR at macro expansion time
+if possible."
+ (define-syntax name
+ (lambda (s)
+ "Return the bytevector corresponding to the given textual
+representation."
+ (syntax-case s ()
+ ((_ str)
+ (string? (syntax->datum #'str))
+ ;; A literal string: do the conversion at expansion time.
+ (with-syntax ((bv (string->bytevector (syntax->datum #'str))))
+ #''bv))
+ ((_ str)
+ #'(string->bytevector str))))))
+
+(define-compile-time-decoder base32 nix-base32-string->bytevector)
+(define-compile-time-decoder base64 base64-decode)
+
;; Crytographic content hash.
(define-immutable-record-type <content-hash>
(%content-hash algorithm value)
@@ -302,25 +321,6 @@ specifications to 'hash'."
(set-record-type-printer! <origin> print-origin)
-(define-syntax-rule (define-compile-time-decoder name string->bytevector)
- "Define NAME as a macro that runs STRING->BYTEVECTOR at macro expansion time
-if possible."
- (define-syntax name
- (lambda (s)
- "Return the bytevector corresponding to the given textual
-representation."
- (syntax-case s ()
- ((_ str)
- (string? (syntax->datum #'str))
- ;; A literal string: do the conversion at expansion time.
- (with-syntax ((bv (string->bytevector (syntax->datum #'str))))
- #''bv))
- ((_ str)
- #'(string->bytevector str))))))
-
-(define-compile-time-decoder base32 nix-base32-string->bytevector)
-(define-compile-time-decoder base64 base64-decode)
-
(define (origin-actual-file-name origin)
"Return the file name of ORIGIN, either its 'file-name' field or the file
name of its URI."
diff --git a/guix/repl.scm b/guix/repl.scm
index 0ace5976cf..94d85815ef 100644
--- a/guix/repl.scm
+++ b/guix/repl.scm
@@ -78,8 +78,14 @@ output port. VERSION is the client's protocol version we are targeting."
(let ((stack (if (repl-prompt)
(make-stack #t handle-exception (repl-prompt))
(make-stack #t))))
+ ;; Note: 'make-stack' returns #f if there's no 'handle-exception'
+ ;; stack frame, which is the case when this file is being
+ ;; interpreted as with 'primitive-load'.
`(exception (arguments ,key ,@(map value->sexp args))
- (stack ,@(map frame->sexp (stack->frames stack))))))
+ (stack ,@(map frame->sexp
+ (if stack
+ (stack->frames stack)
+ '()))))))
(_
;; Protocol (0 0).
`(exception ,key ,@(map value->sexp args)))))
diff --git a/guix/scripts/archive.scm b/guix/scripts/archive.scm
index 1f73fff711..91be1b02e1 100644
--- a/guix/scripts/archive.scm
+++ b/guix/scripts/archive.scm
@@ -318,8 +318,8 @@ the input port."
(warning (G_ "replacing symbolic link ~a with a regular file~%")
%acl-file)
(when (string-prefix? (%store-prefix) (readlink %acl-file))
- (display-hint (G_ "On Guix System, add public keys to the
-@code{authorized-keys} field of your @code{operating-system} instead.")))))
+ (display-hint (G_ "On Guix System, add all @code{authorized-keys} to the
+@code{guix-service-type} service of your @code{operating-system} instead.")))))
(let ((key (read-key))
(acl (current-acl)))
diff --git a/guix/scripts/challenge.scm b/guix/scripts/challenge.scm
index d0a456ac1d..cc9cbe6f27 100644
--- a/guix/scripts/challenge.scm
+++ b/guix/scripts/challenge.scm
@@ -28,6 +28,7 @@
#:use-module ((guix progress) #:hide (dump-port*))
#:use-module (guix serialization)
#:use-module (guix scripts substitute)
+ #:use-module (guix narinfo)
#:use-module (rnrs bytevectors)
#:autoload (guix http-client) (http-fetch)
#:use-module ((guix build syscalls) #:select (terminal-columns))
diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm
index fbc202c658..f4d12f89bf 100644
--- a/guix/scripts/environment.scm
+++ b/guix/scripts/environment.scm
@@ -675,7 +675,7 @@ message if any test fails."
(let* ((root (if (string-prefix? "/" root)
root
(string-append (canonicalize-path (dirname root))
- "/" root))))
+ "/" (basename root)))))
(catch 'system-error
(lambda ()
(symlink target root)
diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm
index 5a865c838d..fa85088ed0 100644
--- a/guix/scripts/publish.scm
+++ b/guix/scripts/publish.scm
@@ -56,6 +56,8 @@
#:use-module (zlib)
#:autoload (lzlib) (call-with-lzip-output-port
make-lzip-output-port)
+ #:autoload (zstd) (call-with-zstd-output-port
+ make-zstd-output-port)
#:use-module (guix cache)
#:use-module (guix ui)
#:use-module (guix scripts)
@@ -588,23 +590,22 @@ requested using POOL."
(define nar
(nar-cache-file cache item #:compression compression))
+ (define (write-compressed-file call-with-compressed-output-port)
+ ;; Note: the file port gets closed along with the compressed port.
+ (call-with-compressed-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))
+
(mkdir-p (dirname nar))
(match (compression-type compression)
('gzip
- ;; Note: the file port gets closed along with the gzip port.
- (call-with-gzip-output-port (open-output-file (string-append nar ".tmp"))
- (lambda (port)
- (write-file item port))
- #:level (compression-level compression)
- #:buffer-size %default-buffer-size)
- (rename-file (string-append nar ".tmp") nar))
+ (write-compressed-file call-with-gzip-output-port))
('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))
+ (write-compressed-file call-with-lzip-output-port))
+ ('zstd
+ (write-compressed-file call-with-zstd-output-port))
('none
;; Cache nars even when compression is disabled so that we can
;; guarantee the TTL (see <https://bugs.gnu.org/28664>.)
@@ -871,6 +872,9 @@ example: \"/foo/bar\" yields '(\"foo\" \"bar\")."
(($ <compression> 'lzip level)
(make-lzip-output-port (response-port response)
#:level level))
+ (($ <compression> 'zstd level)
+ (make-zstd-output-port (response-port response)
+ #:level level))
(($ <compression> 'none)
(response-port response))
(#f
@@ -953,6 +957,7 @@ blocking."
(match string
("gzip" 'gzip)
("lzip" 'lzip)
+ ("zstd" 'zstd)
(_ #f)))
(define (effective-compression requested-type compressions)
diff --git a/guix/scripts/substitute.scm b/guix/scripts/substitute.scm
index e53de8c304..f9bcead045 100755
--- a/guix/scripts/substitute.scm
+++ b/guix/scripts/substitute.scm
@@ -2,6 +2,7 @@
;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2014 Nikita Karetnikov <nikita@karetnikov.org>
;;; Copyright © 2018 Kyle Meyer <kyle@kyleam.com>
+;;; Copyright © 2020 Christopher Baines <mail@cbaines.net>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -21,6 +22,7 @@
(define-module (guix scripts substitute)
#:use-module (guix ui)
#:use-module (guix scripts)
+ #:use-module (guix narinfo)
#:use-module (guix store)
#:use-module (guix utils)
#:use-module (guix combinators)
@@ -67,29 +69,8 @@
#:use-module (web request)
#:use-module (web response)
#:use-module (guix http-client)
- #:export (narinfo-signature->canonical-sexp
-
- narinfo?
- narinfo-path
- narinfo-uris
- narinfo-uri-base
- narinfo-compressions
- narinfo-file-hashes
- narinfo-file-sizes
- narinfo-hash
- narinfo-size
- narinfo-references
- narinfo-deriver
- narinfo-system
- narinfo-signature
-
- narinfo-hash->sha256
- narinfo-best-uri
-
- lookup-narinfos
+ #:export (lookup-narinfos
lookup-narinfos/diverse
- read-narinfo
- write-narinfo
%allow-unauthenticated-substitutes?
%error-to-file-descriptor-4?
@@ -149,10 +130,6 @@ disabled!~%"))
;; How often we want to remove files corresponding to expired cache entries.
(* 7 24 3600))
-(define fields->alist
- ;; The narinfo format is really just like recutils.
- recutils->alist)
-
(define %fetch-timeout
;; Number of seconds after which networking is considered "slow".
5)
@@ -236,191 +213,6 @@ connection (typically PORT) is kept open once data has been fetched from URI."
(leave (G_ "unsupported substitute URI scheme: ~a~%")
(uri->string uri)))))
-
-(define-record-type <narinfo>
- (%make-narinfo path uri-base uris 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
- (compressions narinfo-compressions) ;list of strings
- (file-sizes narinfo-file-sizes) ;list of (integers | #f)
- (file-hashes narinfo-file-hashes)
- (nar-hash narinfo-hash)
- (nar-size narinfo-size)
- (references narinfo-references)
- (deriver narinfo-deriver)
- (system narinfo-system)
- (signature narinfo-signature) ; canonical sexp
- ;; The original contents of a narinfo file. This field is needed because we
- ;; want to preserve the exact textual representation for verification purposes.
- ;; See <https://lists.gnu.org/archive/html/guix-devel/2014-02/msg00340.html>
- ;; for more information.
- (contents narinfo-contents))
-
-(define (narinfo-hash-algorithm+value narinfo)
- "Return two values: the hash algorithm used by NARINFO and its value as a
-bytevector."
- (match (string-tokenize (narinfo-hash narinfo)
- (char-set-complement (char-set #\:)))
- ((algorithm base32)
- (values (lookup-hash-algorithm (string->symbol algorithm))
- (nix-base32-string->bytevector base32)))
- (_
- (raise (formatted-message
- (G_ "invalid narinfo hash: ~s") (narinfo-hash narinfo))))))
-
-(define (narinfo-hash->sha256 hash)
- "If the string HASH denotes a sha256 hash, return it as a bytevector.
-Otherwise return #f."
- (and (string-prefix? "sha256:" hash)
- (nix-base32-string->bytevector (string-drop hash 7))))
-
-(define (narinfo-signature->canonical-sexp str)
- "Return the value of a narinfo's 'Signature' field as a canonical sexp."
- (match (string-split str #\;)
- ((version host-name sig)
- (let ((maybe-number (string->number version)))
- (cond ((not (number? maybe-number))
- (leave (G_ "signature version must be a number: ~s~%")
- version))
- ;; Currently, there are no other versions.
- ((not (= 1 maybe-number))
- (leave (G_ "unsupported signature version: ~a~%")
- maybe-number))
- (else
- (let ((signature (utf8->string (base64-decode sig))))
- (catch 'gcry-error
- (lambda ()
- (string->canonical-sexp signature))
- (lambda (key proc err)
- (leave (G_ "signature is not a valid \
-s-expression: ~s~%")
- signature))))))))
- (x
- (leave (G_ "invalid format of the signature field: ~a~%") x))))
-
-(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
- nar-hash nar-size references deriver system
- signature)
- "Return a new <narinfo> object."
- (define len (length urls))
- (%make-narinfo path cache-url
- ;; Handle the case where URL is a relative URL.
- (map (lambda (url)
- (or (string->uri url)
- (string->uri
- (string-append cache-url "/" url))))
- urls)
- compressions
- (match file-sizes
- (() (make-list len #f))
- ((lst ...) (map string->number lst)))
- (match file-hashes
- (() (make-list len #f))
- ((lst ...) (map string->number lst)))
- nar-hash
- (and=> nar-size string->number)
- (string-tokenize references)
- (match deriver
- ((or #f "") #f)
- (_ deriver))
- system
- (false-if-exception
- (and=> signature narinfo-signature->canonical-sexp))
- str)))
-
-(define* (read-narinfo port #:optional url
- #:key size)
- "Read a narinfo from PORT. If URL is true, it must be a string used to
-build full URIs from relative URIs found while reading PORT. When SIZE is
-true, read at most SIZE bytes from PORT; otherwise, read as much as possible.
-
-No authentication and authorization checks are performed here!"
- (let ((str (utf8->string (if size
- (get-bytevector-n port size)
- (get-bytevector-all port)))))
- (alist->record (call-with-input-string str fields->alist)
- (narinfo-maker str url)
- '("StorePath" "URL" "Compression"
- "FileHash" "FileSize" "NarHash" "NarSize"
- "References" "Deriver" "System"
- "Signature")
- '("URL" "Compression" "FileSize" "FileHash"))))
-
-(define (narinfo-sha256 narinfo)
- "Return the sha256 hash of NARINFO as a bytevector, or #f if NARINFO lacks a
-'Signature' field."
- (define %mandatory-fields
- ;; List of fields that must be signed. If they are not signed, the
- ;; narinfo is considered unsigned.
- '("StorePath" "NarHash" "References"))
-
- (let ((contents (narinfo-contents narinfo)))
- (match (string-contains contents "Signature:")
- (#f #f)
- (index
- (let* ((above-signature (string-take contents index))
- (signed-fields (match (call-with-input-string above-signature
- fields->alist)
- (((fields . values) ...) fields))))
- (and (every (cut member <> signed-fields) %mandatory-fields)
- (sha256 (string->utf8 above-signature))))))))
-
-(define* (valid-narinfo? narinfo #:optional (acl (current-acl))
- #:key verbose?)
- "Return #t if NARINFO's signature is not valid."
- (or (%allow-unauthenticated-substitutes?)
- (let ((hash (narinfo-sha256 narinfo))
- (signature (narinfo-signature narinfo))
- (uri (uri->string (first (narinfo-uris narinfo)))))
- (and hash signature
- (signature-case (signature hash acl)
- (valid-signature #t)
- (invalid-signature
- (when verbose?
- (format (current-error-port)
- "invalid signature for substitute at '~a'~%"
- uri))
- #f)
- (hash-mismatch
- (when verbose?
- (format (current-error-port)
- "hash mismatch for substitute at '~a'~%"
- uri))
- #f)
- (unauthorized-key
- (when verbose?
- (format (current-error-port)
- "substitute at '~a' is signed by an \
-unauthorized party~%"
- uri))
- #f)
- (corrupt-signature
- (when verbose?
- (format (current-error-port)
- "corrupt signature for substitute at '~a'~%"
- uri))
- #f))))))
-
-(define (write-narinfo narinfo port)
- "Write NARINFO to PORT."
- (put-bytevector port (string->utf8 (narinfo-contents narinfo))))
-
-(define (narinfo->string narinfo)
- "Return the external representation of NARINFO."
- (call-with-output-string (cut write-narinfo narinfo <>)))
-
-(define (string->narinfo str cache-uri)
- "Return the narinfo represented by STR. Assume CACHE-URI as the base URI of
-the cache STR originates form."
- (call-with-input-string str (cut read-narinfo <> cache-uri)))
-
(define (narinfo-cache-file cache-url path)
"Return the name of the local file that contains an entry for PATH. The
entry is stored in a sub-directory specific to CACHE-URL."
@@ -742,22 +534,6 @@ information is available locally."
(let ((missing (fetch-narinfos cache missing)))
(append cached (or missing '()))))))
-(define (equivalent-narinfo? narinfo1 narinfo2)
- "Return true if NARINFO1 and NARINFO2 are equivalent--i.e., if they describe
-the same store item. This ignores unnecessary metadata such as the Nar URL."
- (and (string=? (narinfo-hash narinfo1)
- (narinfo-hash narinfo2))
-
- ;; The following is not needed if all we want is to download a valid
- ;; nar, but it's necessary if we want valid narinfo.
- (string=? (narinfo-path narinfo1)
- (narinfo-path narinfo2))
- (equal? (narinfo-references narinfo1)
- (narinfo-references narinfo2))
-
- (= (narinfo-size narinfo1)
- (narinfo-size narinfo2))))
-
(define (lookup-narinfos/diverse caches paths authorized?)
"Look up narinfos for PATHS on all of CACHES, a list of URLS, in that order.
That is, when a cache lacks an AUTHORIZED? narinfo, look it up in the next
@@ -918,11 +694,14 @@ expected by the daemon."
"Reply to COMMAND, a query as written by the daemon to this process's
standard input. Use ACL as the access-control list against which to check
authorized substitutes."
- (define (valid? obj)
- (valid-narinfo? obj acl))
+ (define valid?
+ (if (%allow-unauthenticated-substitutes?)
+ (begin
+ (warn-about-missing-authentication)
- (when (%allow-unauthenticated-substitutes?)
- (warn-about-missing-authentication))
+ (const #t))
+ (lambda (obj)
+ (valid-narinfo? obj acl))))
(match (string-tokenize command)
(("have" paths ..1)
@@ -940,59 +719,6 @@ authorized substitutes."
(wtf
(error "unknown `--query' command" wtf))))
-(define %compression-methods
- ;; Known compression methods and a thunk to determine whether they're
- ;; supported. See 'decompressed-port' in (guix utils).
- `(("gzip" . ,(const #t))
- ("lzip" . ,(const #t))
- ("xz" . ,(const #t))
- ("bzip2" . ,(const #t))
- ("none" . ,(const #t))))
-
-(define (supported-compression? compression)
- "Return true if COMPRESSION, a string, denotes a supported compression
-method."
- (match (assoc-ref %compression-methods compression)
- (#f #f)
- (supported? (supported?))))
-
-(define (compresses-better? compression1 compression2)
- "Return true if COMPRESSION1 generally compresses better than COMPRESSION2;
-this is a rough approximation."
- (match compression1
- ("none" #f)
- ("gzip" (string=? compression2 "none"))
- (_ (or (string=? compression2 "none")
- (string=? compression2 "gzip")))))
-
-(define (narinfo-best-uri narinfo)
- "Select the \"best\" URI to download NARINFO's nar, and return three values:
-the URI, its compression method (a string), and the compressed file size."
- (define choices
- (filter (match-lambda
- ((uri compression file-size)
- (supported-compression? compression)))
- (zip (narinfo-uris narinfo)
- (narinfo-compressions narinfo)
- (narinfo-file-sizes narinfo))))
-
- (define (file-size<? c1 c2)
- (match c1
- ((uri1 compression1 (? integer? file-size1))
- (match c2
- ((uri2 compression2 (? integer? file-size2))
- (< file-size1 file-size2))
- (_ #t)))
- ((uri compression1 #f)
- (match c2
- ((uri2 compression2 _)
- (compresses-better? compression1 compression2))))
- (_ #f))) ;we can't tell
-
- (match (sort choices file-size<?)
- (((uri compression file-size) _ ...)
- (values uri compression file-size))))
-
(define %max-cached-connections
;; Maximum number of connections kept in cache by
;; 'open-connection-for-uri/cached'.
@@ -1079,7 +805,9 @@ DESTINATION is in the store, deduplicate its files. Print a status line on
the current output port."
(define narinfo
(lookup-narinfo cache-urls store-item
- (cut valid-narinfo? <> acl)))
+ (if (%allow-unauthenticated-substitutes?)
+ (const #t)
+ (cut valid-narinfo? <> acl))))
(define destination-in-store?
(string-prefix? (string-append (%store-prefix) "/")
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
index 51c8cf2f76..66225bff35 100644
--- a/guix/scripts/system.scm
+++ b/guix/scripts/system.scm
@@ -705,9 +705,11 @@ checking this by themselves in their 'check' procedure."
image-size
(* 70 (expt 2 20)))
#:mappings mappings))
- ((disk-image)
+ ((image disk-image)
(let* ((base-image (os->image os #:type image-type))
(base-target (image-target base-image)))
+ (when (eq? action 'disk-image)
+ (warning (G_ "'disk-image' is deprecated: use 'image' instead~%")))
(lower-object
(system-image
(image
@@ -779,7 +781,7 @@ and TARGET arguments."
"Perform ACTION for OS. INSTALL-BOOTLOADER? specifies whether to install
bootloader; BOOTLOADER-TAGET is the target for the bootloader; TARGET is the
target root directory; IMAGE-SIZE is the size of the image to be built, for
-the 'vm-image' and 'disk-image' actions. IMAGE-TYPE is the type of image to
+the 'vm-image' and 'image' actions. IMAGE-TYPE is the type of image to
be built. When VOLATILE-ROOT? is #t, the root file system is mounted
volatile.
@@ -968,7 +970,7 @@ Some ACTIONS support additional ARGS.\n"))
(display (G_ "\
vm-image build a freestanding virtual machine image\n"))
(display (G_ "\
- disk-image build a disk image, suitable for a USB stick\n"))
+ image build a Guix System image\n"))
(display (G_ "\
docker-image build a Docker image\n"))
(display (G_ "\
@@ -994,15 +996,15 @@ Some ACTIONS support additional ARGS.\n"))
(display (G_ "
--list-image-types list available image types"))
(display (G_ "
- -t, --image-type=TYPE for 'disk-image', produce an image of TYPE"))
+ -t, --image-type=TYPE for 'image', produce an image of TYPE"))
(display (G_ "
--image-size=SIZE for 'vm-image', produce an image of SIZE"))
(display (G_ "
--no-bootloader for 'init', do not install a bootloader"))
(display (G_ "
- --volatile for 'disk-image', make the root file system volatile"))
+ --volatile for 'image', make the root file system volatile"))
(display (G_ "
- --label=LABEL for 'disk-image', label disk image with LABEL"))
+ --label=LABEL for 'image', label disk image with LABEL"))
(display (G_ "
--save-provenance save provenance information"))
(display (G_ "
@@ -1014,7 +1016,7 @@ Some ACTIONS support additional ARGS.\n"))
(display (G_ "
-N, --network for 'container', allow containers to access the network"))
(display (G_ "
- -r, --root=FILE for 'vm', 'vm-image', 'disk-image', 'container',
+ -r, --root=FILE for 'vm', 'vm-image', 'image', 'container',
and 'build', make FILE a symlink to the result, and
register it as a garbage collector root"))
(display (G_ "
@@ -1143,7 +1145,7 @@ Some ACTIONS support additional ARGS.\n"))
(debug . 0)
(verbosity . #f) ;default
(validate-reconfigure . ,ensure-forward-reconfigure)
- (image-type . raw)
+ (image-type . efi-raw)
(image-size . guess)
(install-bootloader? . #t)
(label . #f)
@@ -1335,7 +1337,7 @@ argument list and OPTS is the option alist."
(alist-cons 'argument arg result)
(let ((action (string->symbol arg)))
(case action
- ((build container vm vm-image disk-image reconfigure init
+ ((build container vm vm-image image disk-image reconfigure init
extension-graph shepherd-graph
list-generations describe
delete-generations roll-back
@@ -1368,7 +1370,8 @@ argument list and OPTS is the option alist."
(exit 1))
(case action
- ((build container vm vm-image disk-image docker-image reconfigure)
+ ((build container vm vm-image image disk-image docker-image
+ reconfigure)
(unless (or (= count 1)
(and expr (= count 0)))
(fail)))
diff --git a/guix/scripts/weather.scm b/guix/scripts/weather.scm
index f28070ddc4..97e4a73802 100644
--- a/guix/scripts/weather.scm
+++ b/guix/scripts/weather.scm
@@ -33,6 +33,7 @@
#:use-module ((guix build syscalls) #:select (terminal-columns))
#:use-module ((guix build utils) #:select (every*))
#:use-module (guix scripts substitute)
+ #:use-module (guix narinfo)
#:use-module (guix http-client)
#:use-module (guix ci)
#:use-module (guix sets)
diff --git a/guix/self.scm b/guix/self.scm
index e2e3198057..15c8ad4eb9 100644
--- a/guix/self.scm
+++ b/guix/self.scm
@@ -59,6 +59,7 @@
("guile-sqlite3" (ref '(gnu packages guile) 'guile-sqlite3))
("guile-zlib" (ref '(gnu packages guile) 'guile-zlib))
("guile-lzlib" (ref '(gnu packages guile) 'guile-lzlib))
+ ("guile-zstd" (ref '(gnu packages guile) 'guile-zstd))
("guile-gcrypt" (ref '(gnu packages gnupg) 'guile-gcrypt))
("gnutls" (ref '(gnu packages tls) 'gnutls))
("gzip" (ref '(gnu packages compression) 'gzip))
@@ -823,6 +824,9 @@ itself."
(define guile-lzlib
(specification->package "guile-lzlib"))
+ (define guile-zstd
+ (specification->package "guile-zstd"))
+
(define guile-gcrypt
(specification->package "guile-gcrypt"))
@@ -836,7 +840,7 @@ itself."
(append-map transitive-package-dependencies
(list guile-gcrypt gnutls guile-git guile-avahi
guile-json guile-semver guile-ssh guile-sqlite3
- guile-zlib guile-lzlib)))
+ guile-zlib guile-lzlib guile-zstd)))
(define *core-modules*
(scheme-node "guix-core"
diff --git a/guix/serialization.scm b/guix/serialization.scm
index 59cd93fb18..9d0739f6c5 100644
--- a/guix/serialization.scm
+++ b/guix/serialization.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -34,7 +34,7 @@
write-bytevector write-string
read-string read-latin1-string read-maybe-utf8-string
write-string-list read-string-list
- write-string-pairs
+ write-string-pairs read-string-pairs
write-store-path read-store-path
write-store-path-list read-store-path-list
(dump . dump-port*)
@@ -166,6 +166,14 @@ substitute invalid byte sequences with question marks. This is a
(write-int (length l) p)
(for-each (cut write-string <> p) l))
+(define (read-string-list p)
+ (let ((len (read-int p)))
+ (unfold (cut >= <> len)
+ (lambda (i)
+ (read-string p))
+ 1+
+ 0)))
+
(define (write-string-pairs l p)
(write-int (length l) p)
(for-each (match-lambda
@@ -174,11 +182,11 @@ substitute invalid byte sequences with question marks. This is a
(write-string second p)))
l))
-(define (read-string-list p)
+(define (read-string-pairs p)
(let ((len (read-int p)))
(unfold (cut >= <> len)
(lambda (i)
- (read-string p))
+ (cons (read-string p) (read-string p)))
1+
0)))
diff --git a/guix/store.scm b/guix/store.scm
index 4da39971b5..e0b15abce3 100644
--- a/guix/store.scm
+++ b/guix/store.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2018 Jan Nieuwenhuizen <janneke@gnu.org>
;;; Copyright © 2019, 2020 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2020 Florian Pelz <pelzflorian@pelzflorian.de>
@@ -114,6 +114,7 @@
query-failed-paths
clear-failed-paths
ensure-path
+ find-roots
add-temp-root
add-indirect-root
add-permanent-root
@@ -340,7 +341,8 @@
(write-string (bytevector->base16-string arg) p))))
(define-syntax read-arg
- (syntax-rules (integer boolean string store-path store-path-list string-list
+ (syntax-rules (integer boolean string store-path
+ store-path-list string-list string-pairs
substitutable-path-list path-info base16)
((_ integer p)
(read-int p))
@@ -354,6 +356,8 @@
(read-store-path-list p))
((_ string-list p)
(read-string-list p))
+ ((_ string-pairs p)
+ (read-string-pairs p))
((_ substitutable-path-list p)
(read-substitutable-path-list p))
((_ path-info p)
@@ -1404,6 +1408,15 @@ running a substitute. As a GC root is not created by the daemon, you may want
to call ADD-TEMP-ROOT on that store path."
boolean)
+(define-operation (find-roots)
+ "Return a list of root/target pairs: for each pair, the first element is the
+GC root file name and the second element is its target in the store.
+
+When talking to a local daemon, this operation is equivalent to the 'gc-roots'
+procedure in (guix store roots), except that the 'find-roots' excludes
+potential roots that do not point to store items."
+ string-pairs)
+
(define-operation (add-temp-root (store-path path))
"Make PATH a temporary root for the duration of the current session.
Return #t."
diff --git a/guix/swh.scm b/guix/swh.scm
index 0b765cc743..f11b7ea2d5 100644
--- a/guix/swh.scm
+++ b/guix/swh.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2020 Jakub Kądziołka <kuba@kadziolka.net>
;;;
;;; This file is part of GNU Guix.
@@ -348,6 +348,7 @@ FALSE-IF-404? is true, return #f upon 404 responses."
(checksums directory-entry-checksums "checksums"
(match-lambda
(#f #f)
+ ((? unspecified?) #f)
(lst (json->checksums lst))))
(id directory-entry-id "dir_id")
(length directory-entry-length)
diff --git a/guix/transformations.scm b/guix/transformations.scm
index 2385d3231e..4e9260350c 100644
--- a/guix/transformations.scm
+++ b/guix/transformations.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -25,6 +25,9 @@
#:autoload (guix download) (download-to-store)
#:autoload (guix git-download) (git-reference? git-reference-url)
#:autoload (guix git) (git-checkout git-checkout? git-checkout-url)
+ #:autoload (guix upstream) (package-latest-release*
+ upstream-source-version
+ upstream-source-signature-urls)
#:use-module (guix utils)
#:use-module (guix memoization)
#:use-module (guix gexp)
@@ -511,6 +514,42 @@ additional patches."
(rewrite obj)
obj)))
+(define (transform-package-latest specs)
+ "Return a procedure that rewrites package graphs such that those in SPECS
+are replaced by their latest upstream version."
+ (define (package-with-latest-upstream p)
+ (let ((source (package-latest-release* p)))
+ (cond ((not source)
+ (warning
+ (G_ "could not determine latest upstream release of '~a'~%")
+ (package-name p))
+ p)
+ ((string=? (upstream-source-version source)
+ (package-version p))
+ p)
+ (else
+ (unless (pair? (upstream-source-signature-urls source))
+ (warning (G_ "cannot authenticate source of '~a', version ~a~%")
+ (package-name p)
+ (upstream-source-version source)))
+
+ ;; TODO: Take 'upstream-source-input-changes' into account.
+ (package
+ (inherit p)
+ (version (upstream-source-version source))
+ (source source))))))
+
+ (define rewrite
+ (package-input-rewriting/spec
+ (map (lambda (spec)
+ (cons spec package-with-latest-upstream))
+ specs)))
+
+ (lambda (obj)
+ (if (package? obj)
+ (rewrite obj)
+ obj)))
+
(define %transformations
;; Transformations that can be applied to things to build. The car is the
;; key used in the option alist, and the cdr is the transformation
@@ -525,7 +564,8 @@ additional patches."
(with-c-toolchain . ,transform-package-toolchain)
(with-debug-info . ,transform-package-with-debug-info)
(without-tests . ,transform-package-tests)
- (with-patch . ,transform-package-patches)))
+ (with-patch . ,transform-package-patches)
+ (with-latest . ,transform-package-latest)))
(define (transformation-procedure key)
"Return the transformation procedure associated with KEY, a symbol such as
@@ -567,6 +607,8 @@ additional patches."
(parser 'without-tests))
(option '("with-patch") #t #f
(parser 'with-patch))
+ (option '("with-latest") #t #f
+ (parser 'with-latest))
(option '("help-transform") #f #f
(lambda _
@@ -599,6 +641,9 @@ additional patches."
--with-patch=PACKAGE=FILE
add FILE to the list of patches of PACKAGE"))
(display (G_ "
+ --with-latest=PACKAGE
+ use the latest upstream release of PACKAGE"))
+ (display (G_ "
--with-c-toolchain=PACKAGE=TOOLCHAIN
build PACKAGE and its dependents with TOOLCHAIN"))
(display (G_ "
diff --git a/guix/upstream.scm b/guix/upstream.scm
index a8ed1d81cd..accd8967d8 100644
--- a/guix/upstream.scm
+++ b/guix/upstream.scm
@@ -31,8 +31,8 @@
#:use-module (guix base32)
#:use-module (guix gexp)
#:use-module (guix store)
- #:use-module ((guix derivations)
- #:select (built-derivations derivation->output-path))
+ #:use-module ((guix derivations) #:select (built-derivations derivation->output-path))
+ #:autoload (gcrypt hash) (port-sha256)
#:use-module (guix monads)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-9)
@@ -248,6 +248,9 @@ correspond to the same version."
'()
(importer-modules))))
+;; Tests need to mock this variable so mark it as "non-declarative".
+(set! %updaters %updaters)
+
(define* (lookup-updater package
#:optional (updaters (force %updaters)))
"Return an updater among UPDATERS that matches PACKAGE, or #f if none of
@@ -351,6 +354,27 @@ values: 'interactive' (default), 'always', and 'never'."
data url)
#f)))))))
+(define-gexp-compiler (upstream-source-compiler (source <upstream-source>)
+ system target)
+ "Download SOURCE from its first URL and lower it as a fixed-output
+derivation that would fetch it."
+ (mlet* %store-monad ((url -> (first (upstream-source-urls source)))
+ (signature
+ -> (and=> (upstream-source-signature-urls source)
+ first))
+ (tarball ((store-lift download-tarball) url signature)))
+ (unless tarball
+ (raise (formatted-message (G_ "failed to fetch source from '~a'")
+ url)))
+
+ ;; Instead of returning TARBALL, return a fixed-output derivation that
+ ;; would be able to re-download it. In practice, since TARBALL is already
+ ;; in the store, no extra download will happen, but having the derivation
+ ;; in store improves provenance tracking.
+ (let ((hash (call-with-input-file tarball port-sha256)))
+ (url-fetch url 'sha256 hash (store-path-package-name tarball)
+ #:system system))))
+
(define (find2 pred lst1 lst2)
"Like 'find', but operate on items from both LST1 and LST2. Return two
values: the item from LST1 and the item from LST2 that match PRED."
diff --git a/guix/utils.scm b/guix/utils.scm
index 0df46f1062..f8b05e7e80 100644
--- a/guix/utils.scm
+++ b/guix/utils.scm
@@ -110,7 +110,6 @@
edit-expression
filtered-port
- compressed-port
decompressed-port
call-with-decompressed-port
compressed-output-port
@@ -211,7 +210,13 @@ buffered data is lost."
"Return the lzip port produced by calling PROC (a symbol) on PORT and ARGS.
Raise an error if lzlib support is missing."
(let ((make-port (module-ref (resolve-interface '(lzlib)) proc)))
- (values (make-port port) '())))
+ (make-port port)))
+
+(define (zstd-port proc port . args)
+ "Return the zstd port produced by calling PROC (a symbol) on PORT and ARGS.
+Raise an error if zstd support is missing."
+ (let ((make-port (module-ref (resolve-interface '(zstd)) proc)))
+ (make-port port)))
(define (decompressed-port compression input)
"Return an input port where INPUT is decompressed according to COMPRESSION,
@@ -223,17 +228,7 @@ a symbol such as 'xz."
('gzip (filtered-port `(,%gzip "-dc") input))
('lzip (values (lzip-port 'make-lzip-input-port input)
'()))
- (_ (error "unsupported compression scheme" compression))))
-
-(define (compressed-port compression input)
- "Return an input port where INPUT is compressed according to COMPRESSION,
-a symbol such as 'xz."
- (match compression
- ((or #f 'none) (values input '()))
- ('bzip2 (filtered-port `(,%bzip2 "-c") input))
- ('xz (filtered-port `(,%xz "-c") input))
- ('gzip (filtered-port `(,%gzip "-c") input))
- ('lzip (values (lzip-port 'make-lzip-input-port/compressed input)
+ ('zstd (values (zstd-port 'make-zstd-input-port input)
'()))
(_ (error "unsupported compression scheme" compression))))
@@ -294,6 +289,8 @@ program--e.g., '(\"--fast\")."
('gzip (filtered-output-port `(,%gzip "-c" ,@options) output))
('lzip (values (lzip-port 'make-lzip-output-port output)
'()))
+ ('zstd (values (zstd-port 'make-zstd-output-port output)
+ '()))
(_ (error "unsupported compression scheme" compression))))
(define* (call-with-compressed-output-port compression port proc