summaryrefslogtreecommitdiff
path: root/guix
diff options
context:
space:
mode:
authorMaxim Cournoyer <maxim.cournoyer@gmail.com>2022-01-25 23:36:11 -0500
committerMaxim Cournoyer <maxim.cournoyer@gmail.com>2022-01-25 23:48:37 -0500
commit0d41fe4855588fb659b8adafe215d5573517a79b (patch)
tree38b274bd03375f4fa5b7d3a9fb3f64a19786bef2 /guix
parent7c57821c68d199ad56a8ed750b36eccc7ef238dd (diff)
parent1a5302435ff0d2822b823f5a6fe01faa7a85c629 (diff)
Merge branch 'staging' into core-updates.
With "conflicts" resolved in (mostly in favor of master/staging): gnu/packages/admin.scm gnu/packages/gnuzilla.scm gnu/packages/gtk.scm gnu/packages/kerberos.scm gnu/packages/linux.scm guix/lint.scm
Diffstat (limited to 'guix')
-rw-r--r--guix/build-system/clojure.scm9
-rw-r--r--guix/build-system/cmake.scm3
-rw-r--r--guix/build-system/go.scm26
-rw-r--r--guix/build-system/guile.scm3
-rw-r--r--guix/build-system/linux-module.scm93
-rw-r--r--guix/build-system/meson.scm13
-rw-r--r--guix/build-system/node.scm9
-rw-r--r--guix/build-system/qt.scm3
-rw-r--r--guix/build/clojure-build-system.scm43
-rw-r--r--guix/build/clojure-utils.scm12
-rw-r--r--guix/build/compile.scm32
-rw-r--r--guix/build/gnu-build-system.scm2
-rw-r--r--guix/build/go-build-system.scm26
-rw-r--r--guix/build/julia-build-system.scm33
-rw-r--r--guix/build/node-build-system.scm236
-rw-r--r--guix/build/syscalls.scm2
-rw-r--r--guix/build/utils.scm8
-rw-r--r--guix/channels.scm2
-rw-r--r--guix/ci.scm4
-rw-r--r--guix/combinators.scm50
-rw-r--r--guix/cpu.scm143
-rw-r--r--guix/git.scm14
-rw-r--r--guix/hash.scm73
-rw-r--r--guix/import/cran.scm38
-rw-r--r--guix/import/elpa.scm53
-rw-r--r--guix/import/git.scm22
-rw-r--r--guix/import/github.scm52
-rw-r--r--guix/import/go.scm85
-rw-r--r--guix/import/minetest.scm25
-rw-r--r--guix/import/texlive.scm61
-rw-r--r--guix/inferior.scm6
-rw-r--r--guix/lint.scm2
-rw-r--r--guix/packages.scm10
-rw-r--r--guix/scripts/environment.scm7
-rw-r--r--guix/scripts/hash.scm31
-rw-r--r--guix/scripts/home.scm6
-rw-r--r--guix/scripts/home/import.scm4
-rw-r--r--guix/scripts/import/go.scm69
-rw-r--r--guix/scripts/import/texlive.scm4
-rw-r--r--guix/scripts/offload.scm5
-rw-r--r--guix/scripts/package.scm5
-rw-r--r--guix/scripts/refresh.scm10
-rw-r--r--guix/scripts/shell.scm161
-rw-r--r--guix/scripts/style.scm421
-rwxr-xr-xguix/scripts/substitute.scm2
-rw-r--r--guix/scripts/system.scm50
-rw-r--r--guix/self.scm8
-rw-r--r--guix/tests/git.scm25
-rw-r--r--guix/tests/gnupg.scm30
-rw-r--r--guix/transformations.scm213
-rw-r--r--guix/ui.scm17
-rw-r--r--guix/upstream.scm81
-rw-r--r--guix/utils.scm5
53 files changed, 1815 insertions, 532 deletions
diff --git a/guix/build-system/clojure.scm b/guix/build-system/clojure.scm
index 39b7f44e89..2a0713d297 100644
--- a/guix/build-system/clojure.scm
+++ b/guix/build-system/clojure.scm
@@ -81,8 +81,7 @@
#:allow-other-keys
#:rest arguments)
"Return a bag for NAME."
- (let ((private-keywords '(#:source #:target
- #:inputs #:native-inputs
+ (let ((private-keywords '(#:target #:inputs #:native-inputs
#:clojure #:jdk #:zip)))
(if target
@@ -108,8 +107,10 @@
#:key
source
(source-dirs `',%source-dirs)
+ (java-source-dirs `',%java-source-dirs)
(test-dirs `',%test-dirs)
(compile-dir %compile-dir)
+ (java-compile-dir %java-compile-dir)
(jar-names `',(package-name->jar-names name))
(main-class %main-class)
@@ -143,9 +144,11 @@
#:source #+source
#:source-dirs #$source-dirs
+ #:java-source-dirs #$java-source-dirs
#:test-dirs #$test-dirs
#:compile-dir #$compile-dir
-
+ #:java-compile-dir #$java-compile-dir
+
#:jar-names #$jar-names
#:main-class #$main-class
#:omit-source? #$omit-source?
diff --git a/guix/build-system/cmake.scm b/guix/build-system/cmake.scm
index 2056c04153..0aabc95b90 100644
--- a/guix/build-system/cmake.scm
+++ b/guix/build-system/cmake.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013, 2014, 2015, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013-2015, 2020-2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2013 Cyril Roelandt <tipecaml@gmail.com>
;;; Copyright © 2017 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2020 Efraim Flashner <efraim@flashner.co.il>
@@ -240,6 +240,7 @@ build system."
#:parallel-tests? #$parallel-tests?
#:validate-runpath? #$validate-runpath?
#:patch-shebangs? #$patch-shebangs?
+ #:make-dynamic-linker-cache? #f ;cross-compiling
#:strip-binaries? #$strip-binaries?
#:strip-flags #$strip-flags
#:strip-directories #$strip-directories))))
diff --git a/guix/build-system/go.scm b/guix/build-system/go.scm
index 18824c79d9..5e0e5bbad3 100644
--- a/guix/build-system/go.scm
+++ b/guix/build-system/go.scm
@@ -2,8 +2,9 @@
;;; Copyright © 2016 Petter <petter@mykolab.ch>
;;; Copyright © 2017 Leo Famulari <leo@famulari.name>
;;; Copyright © 2020 Jakub Kądziołka <kuba@kadziolka.net>
-;;; Copyright © 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2021-2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2021 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -112,6 +113,9 @@ commit hash and its date rather than a proper release tag."
(let ((go (resolve-interface '(gnu packages golang))))
(module-ref go 'go)))
+(define (make-go-std)
+ (module-ref (resolve-interface '(gnu packages golang)) 'make-go-std))
+
(define* (lower name
#:key source inputs native-inputs outputs system target
(go (default-go))
@@ -121,6 +125,14 @@ commit hash and its date rather than a proper release tag."
(define private-keywords
'(#:target #:go #:inputs #:native-inputs))
+ (define inputs-with-cache
+ ;; XXX: Avoid a circular dependency. This should be rewritten with
+ ;; 'package-mapping' or similar.
+ (let ((go-std-name (string-append (package-name go) "-std")))
+ (if (string-prefix? go-std-name name)
+ inputs
+ (cons `(,go-std-name ,((make-go-std) go)) inputs))))
+
(bag
(name name)
(system system)
@@ -130,7 +142,7 @@ commit hash and its date rather than a proper release tag."
'())
,@`(("go" ,go))
,@native-inputs
- ,@(if target '() inputs)
+ ,@(if target '() inputs-with-cache)
,@(if target
;; Use the standard cross inputs of
;; 'gnu-build-system'.
@@ -138,7 +150,7 @@ commit hash and its date rather than a proper release tag."
'())
;; Keep the standard inputs of 'gnu-build-system'.
,@(standard-packages)))
- (host-inputs (if target inputs '()))
+ (host-inputs (if target inputs-with-cache '()))
;; The cross-libc is really a target package, but for bootstrapping
;; reasons, we can't put it in 'host-inputs'. Namely, 'cross-gcc' is a
@@ -172,7 +184,8 @@ commit hash and its date rather than a proper release tag."
(imported-modules %go-build-system-modules)
(modules '((guix build go-build-system)
(guix build union)
- (guix build utils))))
+ (guix build utils)))
+ (substitutable? #t))
(define builder
(with-imported-modules imported-modules
#~(begin
@@ -182,6 +195,7 @@ commit hash and its date rather than a proper release tag."
#:system #$system
#:phases #$phases
#:outputs #$(outputs->gexp outputs)
+ #:substitutable? #$substitutable?
#:goarch #$goarch
#:goos #$goos
#:search-paths '#$(sexp->gexp
@@ -222,7 +236,8 @@ commit hash and its date rather than a proper release tag."
(imported-modules %go-build-system-modules)
(modules '((guix build go-build-system)
(guix build union)
- (guix build utils))))
+ (guix build utils)))
+ (substitutable? #t))
"Cross-build NAME using GO, where TARGET is a GNU triplet and with INPUTS."
(define builder
#~(begin
@@ -261,6 +276,7 @@ commit hash and its date rather than a proper release tag."
#:unpack-path #$unpack-path
#:build-flags #$build-flags
#:tests? #$tests?
+ #:make-dynamic-linker-cache? #f ;cross-compiling
#:allow-go-reference? #$allow-go-reference?
#:inputs %build-inputs)))
diff --git a/guix/build-system/guile.scm b/guix/build-system/guile.scm
index f64f214675..36a88e181a 100644
--- a/guix/build-system/guile.scm
+++ b/guix/build-system/guile.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2018, 2019, 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2018-2019, 2021-2022 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -162,6 +162,7 @@
#:native-search-paths '#$(map
search-path-specification->sexp
native-search-paths)
+ #:make-dynamic-linker-cache? #f ;cross-compiling
#:phases #$phases))))
(mlet %store-monad ((guile (package->derivation (or guile (default-guile))
diff --git a/guix/build-system/linux-module.scm b/guix/build-system/linux-module.scm
index 57fce8e96e..e82a9ca65c 100644
--- a/guix/build-system/linux-module.scm
+++ b/guix/build-system/linux-module.scm
@@ -61,53 +61,52 @@
`(("linux" ,linux)))
(arguments
(substitute-keyword-arguments (package-arguments linux)
- ((#:phases phases)
- `(modify-phases ,phases
- (replace 'build
- (lambda _
- (invoke "make" "modules_prepare")))
- (delete 'strip) ; faster.
- (replace 'install
- (lambda* (#:key inputs outputs #:allow-other-keys)
- (let* ((out (assoc-ref outputs "out"))
- (out-lib-build (string-append out "/lib/modules/build")))
- ;; Delete some huge items that we probably don't need.
- ;; TODO: Only preserve the minimum, i.e. [Kbuild], Kconfig,
- ;; scripts, include, ".config".
- (copy-recursively "." out-lib-build)
- (for-each (lambda (name)
- (when (file-exists? name)
- (delete-file-recursively name)))
- (map (lambda (name)
- (string-append out-lib-build "/" name))
- '("arch" ; 137 MB
- ;"tools" ; 44 MB ; Note: is built by our 'build phase.
- "tools/testing" ; 14 MB
- "tools/perf" ; 17 MB
- "drivers" ; 600 MB
- "Documentation" ; 52 MB
- "fs" ; 43 MB
- "net" ; 33 MB
- "samples" ; 2 MB
- "sound"))) ; 40 MB
- ;; Reinstate arch/**/dts since "scripts/dtc" depends on it.
- ;; Reinstate arch/**/include directories.
- ;; Reinstate arch/**/Makefile.
- ;; Reinstate arch/**/module.lds.
- (for-each
- (lambda (name)
- (mkdir-p (dirname (string-append out-lib-build "/" name)))
- (copy-recursively name
- (string-append out-lib-build "/" name)))
- (append (find-files "arch" "^(dts|include)$" #:directories? #t)
- (find-files "arch" "^(Makefile|module.lds)$")))
- (let* ((linux (assoc-ref inputs "linux")))
- (install-file (string-append linux "/System.map")
- out-lib-build)
- (let ((source (string-append linux "/Module.symvers")))
- (when (file-exists? source)
- (install-file source out-lib-build))))
- #t)))))))))
+ ((#:phases phases)
+ #~(modify-phases #$phases
+ (replace 'build
+ (lambda _
+ (invoke "make" "modules_prepare")))
+ (delete 'strip) ; faster
+ (replace 'install
+ (lambda* (#:key inputs #:allow-other-keys)
+ (let ((out-lib-build (string-append #$output "/lib/modules/build")))
+ ;; Delete some huge items that we probably don't need.
+ ;; TODO: Only preserve the minimum, i.e. [Kbuild], Kconfig,
+ ;; scripts, include, ".config".
+ (copy-recursively "." out-lib-build)
+ (for-each (lambda (name)
+ (when (file-exists? name)
+ (delete-file-recursively name)))
+ (map (lambda (name)
+ (string-append out-lib-build "/" name))
+ '("arch" ; 137 MB
+ ;;"tools" ; 44 MB built by our 'build phase
+ "tools/testing" ; 14 MB
+ "tools/perf" ; 17 MB
+ "drivers" ; 600 MB
+ "Documentation" ; 52 MB
+ "fs" ; 43 MB
+ "net" ; 33 MB
+ "samples" ; 2 MB
+ "sound"))) ; 40 MB
+ ;; Reinstate arch/**/dts since "scripts/dtc" depends on it.
+ ;; Reinstate arch/**/include directories.
+ ;; Reinstate arch/**/Makefile.
+ ;; Reinstate arch/**/module.lds.
+ (for-each
+ (lambda (name)
+ (mkdir-p (dirname (string-append out-lib-build "/" name)))
+ (copy-recursively name
+ (string-append out-lib-build "/" name)))
+ (append (find-files "arch" "^(dts|include)$"
+ #:directories? #t)
+ (find-files "arch" "^(Makefile|module.lds)$")))
+ (let* ((linux #$(this-package-input "linux")))
+ (install-file (string-append linux "/System.map")
+ out-lib-build)
+ (let ((source (string-append linux "/Module.symvers")))
+ (when (file-exists? source)
+ (install-file source out-lib-build)))))))))))))
(define* (lower name
#:key source inputs native-inputs outputs
diff --git a/guix/build-system/meson.scm b/guix/build-system/meson.scm
index ba7441a3eb..ad604f8871 100644
--- a/guix/build-system/meson.scm
+++ b/guix/build-system/meson.scm
@@ -287,6 +287,19 @@ SOURCE has a 'meson.build' file."
#~(begin
(use-modules #$@(sexp->gexp modules))
+ (define %build-host-inputs
+ #+(input-tuples->gexp build-inputs))
+
+ (define %build-target-inputs
+ (append #$(input-tuples->gexp host-inputs)
+ #+(input-tuples->gexp target-inputs)))
+
+ (define %build-inputs
+ (append %build-host-inputs %build-target-inputs))
+
+ (define %outputs
+ #$(outputs->gexp outputs))
+
(define build-phases
#$(let ((phases (if (pair? phases) (sexp->gexp phases) phases)))
(if glib-or-gtk?
diff --git a/guix/build-system/node.scm b/guix/build-system/node.scm
index 735f8dd06e..24bd677bfc 100644
--- a/guix/build-system/node.scm
+++ b/guix/build-system/node.scm
@@ -2,6 +2,8 @@
;;; Copyright © 2016 Jelle Licht <jlicht@fsfe.org>
;;; Copyright © 2019 Timothy Sample <samplet@ngyro.com>
;;; Copyright © 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2021 Pierre Langlois <pierre.langlois@gmx.com>
+;;; Copyright © 2021 Philip McGrath <philip@philipmcgrath.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -61,10 +63,15 @@
`(("source" ,source))
'())
,@inputs
-
;; Keep the standard inputs of 'gnu-build-system'.
,@(standard-packages)))
(build-inputs `(("node" ,node)
+ ;; Many packages with native addons need
+ ;; libuv headers. The libuv version must
+ ;; be exactly the same as for the node
+ ;; package we are adding implicitly,
+ ;; so we take care of adding libuv, too.
+ ("libuv" ,@(assoc-ref (package-inputs node) "libuv"))
,@native-inputs))
(outputs outputs)
(build node-build)
diff --git a/guix/build-system/qt.scm b/guix/build-system/qt.scm
index 003a065aa6..a0b968cef3 100644
--- a/guix/build-system/qt.scm
+++ b/guix/build-system/qt.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013, 2014, 2015, 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013-2015, 2021-2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2013 Cyril Roelandt <tipecaml@gmail.com>
;;; Copyright © 2017 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2019 Hartmut Goebel <h.goebel@crazy-compilers.com>
@@ -247,6 +247,7 @@ build system."
#:parallel-tests? #$parallel-tests?
#:validate-runpath? #$validate-runpath?
#:patch-shebangs? #$patch-shebangs?
+ #:make-dynamic-linker-cache? #f ;cross-compiling
#:strip-binaries? #$strip-binaries?
#:strip-flags #$strip-flags
#:strip-directories #$strip-directories))))
diff --git a/guix/build/clojure-build-system.scm b/guix/build/clojure-build-system.scm
index d8f7c89f85..7d494078ea 100644
--- a/guix/build/clojure-build-system.scm
+++ b/guix/build/clojure-build-system.scm
@@ -34,8 +34,24 @@
;;
;; Code:
+(define* (compile-java #:key
+ java-source-dirs java-compile-dir
+ #:allow-other-keys)
+ "Compile java sources for use in clojure-build-system."
+ (let ((java-files (append-map (lambda (dir)
+ (find-files dir "\\.java$"))
+ java-source-dirs)))
+ (mkdir-p java-compile-dir)
+ (when (not (null? java-files))
+ (apply invoke
+ "javac"
+ "-verbose"
+ "-d" java-compile-dir
+ java-files))))
+
(define* (build #:key
- source-dirs compile-dir
+ source-dirs java-source-dirs
+ compile-dir java-compile-dir
jar-names main-class omit-source?
aot-include aot-exclude
#:allow-other-keys)
@@ -46,19 +62,24 @@
#:all-list libs)))
(mkdir-p compile-dir)
(eval-with-clojure `(run! compile ',libs*)
- source-dirs)
+ (cons* compile-dir
+ java-compile-dir
+ source-dirs))
(let ((source-dir-files-alist (map (lambda (dir)
(cons dir (find-files* dir)))
- source-dirs))
+ (append source-dirs
+ java-source-dirs)))
;; workaround transitive compilation in Clojure
(classes (filter (lambda (class)
(any (cut compiled-from? class <>)
libs*))
(find-files* compile-dir))))
- (for-each (cut create-jar <> (cons (cons compile-dir classes)
- (if omit-source?
- '()
- source-dir-files-alist))
+ (for-each (cut create-jar <> (cons* (cons compile-dir classes)
+ (cons java-compile-dir
+ (find-files* java-compile-dir))
+ (if omit-source?
+ '()
+ source-dir-files-alist))
#:main-class main-class)
jar-names)
#t)))
@@ -78,8 +99,11 @@ priority over TEST-INCLUDE."
(for-each (lambda (jar)
(eval-with-clojure `(do (apply require
'(clojure.test ,@libs*))
- (apply clojure.test/run-tests
- ',libs*))
+ (if (clojure.test/successful?
+ (apply clojure.test/run-tests
+ ',libs*))
+ (System/exit 0)
+ (System/exit 1)))
(cons jar test-dirs)))
jar-names)))
#t)
@@ -91,6 +115,7 @@ priority over TEST-INCLUDE."
(define-with-docs %standard-phases
"Standard build phases for clojure-build-system."
(modify-phases %standard-phases@ant
+ (add-before 'build 'compile-java compile-java)
(replace 'build build)
(replace 'check check)
(replace 'install install)
diff --git a/guix/build/clojure-utils.scm b/guix/build/clojure-utils.scm
index a9ffad3c8f..c5322141d3 100644
--- a/guix/build/clojure-utils.scm
+++ b/guix/build/clojure-utils.scm
@@ -32,8 +32,10 @@
install-doc
%source-dirs
+ %java-source-dirs
%test-dirs
%compile-dir
+ %java-compile-dir
package-name->jar-names
%main-class
%omit-source?
@@ -101,6 +103,10 @@ DOC-REGEX can be compiled or uncompiled."
"A default list of source directories."
'("src/"))
+(define-with-docs %java-source-dirs
+ "A default list of java source directories."
+ '())
+
(define-with-docs %test-dirs
"A default list of test directories."
'("test/"))
@@ -109,6 +115,10 @@ DOC-REGEX can be compiled or uncompiled."
"Default directory for holding class files."
"classes/")
+(define-with-docs %java-compile-dir
+ "Default directory for holding java class files."
+ "java-classes/")
+
(define (package-name->jar-names name)
"Given NAME, a package name like \"foo-0.9.1b\",
return the list of default jar names: (\"foo-0.9.1b.jar\" \"foo.jar\")."
@@ -135,7 +145,7 @@ all libraries found under the source directories."
(define-with-docs %aot-exclude
"A default list of symbols deciding what not to compile.
See the doc string of '%aot-include' for more details."
- '())
+ '(data-readers))
(define-with-docs %tests?
"Enable tests by default."
diff --git a/guix/build/compile.scm b/guix/build/compile.scm
index b86ec3b743..5b27b55d02 100644
--- a/guix/build/compile.scm
+++ b/guix/build/compile.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013, 2014, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013-2014, 2016-2020, 2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2015 Taylan Ulrich Bayırlı/Kammer <taylanbayirli@gmail.com>
;;;
;;; This file is part of GNU Guix.
@@ -37,6 +37,21 @@
;;;
;;; Code:
+(define (clear-keyword-arguments keywords args)
+ "Set to #f the value associated with each of the KEYWORDS in ARGS."
+ (let loop ((args args)
+ (result '()))
+ (match args
+ (()
+ (reverse result))
+ (((? keyword? kw) arg . rest)
+ (loop rest
+ (if (memq kw keywords)
+ (cons* #f kw result)
+ (cons* arg kw result))))
+ ((head . tail)
+ (loop tail (cons head result))))))
+
(define optimizations-for-level
(or (and=> (false-if-exception
(resolve-interface '(system base optimize)))
@@ -60,9 +75,18 @@
(loop rest `(#f ,kw ,@result))))))
(lambda (level)
- (if (<= level 1)
- %lightweight-optimizations
- %default-optimizations)))))
+ ;; In the upcoming Guile 3.0.8, .go files include code of their
+ ;; inlinable exports and free variables are resolved at compile time
+ ;; (both are enabled at -O1) to permit cross-module inlining
+ ;; (enabled at -O2). Unfortunately, this currently leads to
+ ;; non-reproducible and more expensive builds, so we turn it off
+ ;; here:
+ ;; <https://wingolog.org/archives/2021/05/13/cross-module-inlining-in-guile>.
+ (clear-keyword-arguments '(#:inlinable-exports? #:resolve-free-vars?
+ #:cross-module-inlining?)
+ (if (<= level 1)
+ %lightweight-optimizations
+ %default-optimizations))))))
(define (supported-warning-type? type)
"Return true if TYPE, a symbol, denotes a supported warning type."
diff --git a/guix/build/gnu-build-system.scm b/guix/build/gnu-build-system.scm
index d0f7413268..d84411c090 100644
--- a/guix/build/gnu-build-system.scm
+++ b/guix/build/gnu-build-system.scm
@@ -598,6 +598,8 @@ and 'man/'. This phase moves directories to the right place if needed."
(string-suffix? ".tgz" file))
(gzip-file? file)))
#:stat lstat)))
+ ;; Ensure the files are writable.
+ (for-each make-file-writable files)
(for-each reset-gzip-timestamp files)))
(match outputs
diff --git a/guix/build/go-build-system.scm b/guix/build/go-build-system.scm
index 4768ee8562..7f25e05d0d 100644
--- a/guix/build/go-build-system.scm
+++ b/guix/build/go-build-system.scm
@@ -5,6 +5,7 @@
;;; Copyright © 2020 Jack Hill <jackhill@jackhill.us>
;;; Copyright © 2020 Jakub Kądziołka <kuba@kadziolka.net>
;;; Copyright © 2020, 2021 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -138,9 +139,28 @@ of the package being built and its dependencies, and GOBIN, which determines
where executables (\"commands\") are installed to. This phase is sometimes used
by packages that use (guix build-system gnu) but have a handful of Go
dependencies, so it should be self-contained."
- ;; The Go cache is required starting in Go 1.12. We don't actually use it but
- ;; we need it to be a writable directory.
- (setenv "GOCACHE" "/tmp/go-cache")
+ (define (search-input-directories dir)
+ (filter directory-exists?
+ (map (match-lambda
+ ((name . directory)
+ (string-append directory "/" dir)))
+ inputs)))
+
+ ;; Seed the Go build cache with the build caches from input packages.
+ (let ((cache (string-append (getcwd) "/go-build")))
+ (setenv "GOCACHE" cache)
+ (union-build cache
+ (search-input-directories "/var/cache/go/build")
+ ;; Creating all directories isn't that bad, because there are
+ ;; only ever 256 of them.
+ #:create-all-directories? #t
+ #:log-port (%make-void-port "w"))
+
+ ;; Tell Go that the cache was recently trimmed, so it doesn't try to.
+ (call-with-output-file (string-append cache "/trim.txt")
+ (lambda (port)
+ (format port "~a" (current-time)))))
+
;; Using the current working directory as GOPATH makes it easier for packagers
;; who need to manipulate the unpacked source code.
(setenv "GOPATH" (getcwd))
diff --git a/guix/build/julia-build-system.scm b/guix/build/julia-build-system.scm
index b4e0044567..03d669be64 100644
--- a/guix/build/julia-build-system.scm
+++ b/guix/build/julia-build-system.scm
@@ -1,7 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2019, 2020 Nicolò Balzarotti <nicolo@nixo.xyz>
;;; Copyright © 2021 Jean-Baptiste Volatier <jbv@pm.me>
-;;; Copyright © 2021 Simon Tournier <zimon.toutoune@gmail.com>
+;;; Copyright © 2021, 2022 Simon Tournier <zimon.toutoune@gmail.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -27,8 +27,8 @@
#:use-module (ice-9 regex)
#:use-module (ice-9 rdelim)
#:use-module (ice-9 popen)
+ #:use-module (srfi srfi-1)
#:export (%standard-phases
- julia-create-package-toml
julia-build))
;; Commentary:
@@ -138,6 +138,8 @@ Project.toml)."
(define* (link-depot #:key source inputs outputs
julia-package-name julia-package-uuid #:allow-other-keys)
(let* ((out (assoc-ref outputs "out"))
+ (name+version (strip-store-file-name out))
+ (version (last (string-split name+version #\-)))
(package-name (or
julia-package-name
(project.toml->name "Project.toml")))
@@ -148,6 +150,14 @@ Project.toml)."
println(Base.version_slug(Base.UUID(\"~a\"),
Base.SHA1(Pkg.GitTools.tree_hash(\".\"))))" uuid)))
(slug (string-trim-right (get-string-all pipe))))
+ ;; Few packages do not have the regular Project.toml file, then when they
+ ;; are propagated, dependencies do not find them and an raise error.
+ (unless (file-exists? "Project.toml")
+ (julia-create-package-toml (getcwd)
+ julia-package-name julia-package-uuid
+ version
+ #:file "Project.toml"))
+
;; When installing a package, julia looks first at in the JULIA_DEPOT_PATH
;; for a path like packages/PACKAGE/XXXX
;; Where XXXX is a slug encoding the package UUID and SHA1 of the files
@@ -157,17 +167,16 @@ println(Base.version_slug(Base.UUID(\"~a\"),
(symlink package-dir (string-append out "/share/julia/packages/"
package-name "/" slug))))
-(define (julia-create-package-toml outputs source
- name uuid version
- deps)
- "Some packages are not using the new Package.toml dependency specifications.
-Write this file manually, so that Julia can find its dependencies."
+(define* (julia-create-package-toml location
+ name uuid version
+ #:optional
+ (deps '())
+ #:key
+ (file "Project.toml"))
+ "Some packages are not using the new Project.toml dependency specifications.
+Write this FILE manually, so that Julia can find its dependencies."
(let ((f (open-file
- (string-append
- (assoc-ref outputs "out")
- %package-path
- (string-append
- name "/Project.toml"))
+ (string-append location "/" file)
"w")))
(display (string-append
"
diff --git a/guix/build/node-build-system.scm b/guix/build/node-build-system.scm
index 70a367618e..bee3792e93 100644
--- a/guix/build/node-build-system.scm
+++ b/guix/build/node-build-system.scm
@@ -2,6 +2,8 @@
;;; Copyright © 2015 David Thompson <davet@gnu.org>
;;; Copyright © 2016, 2020 Jelle Licht <jlicht@fsfe.org>
;;; Copyright © 2019, 2021 Timothy Sample <samplet@ngyro.com>
+;;; Copyright © 2021, 2022 Philip McGrath <philip@philipmcgrath.com>
+;;; Copyright © 2022 Liliana Marie Prikler <liliana.prikler@gmail.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -23,16 +25,108 @@
#:use-module (guix build utils)
#:use-module (guix build json)
#:use-module (ice-9 ftw)
+ #:use-module (ice-9 regex)
#:use-module (ice-9 match)
#:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-71)
#:export (%standard-phases
+ with-atomic-json-file-replacement
+ delete-dependencies
node-build))
-;; Commentary:
-;;
-;; Builder-side code of the standard Node/NPM package install procedure.
-;;
-;; Code:
+(define (with-atomic-json-file-replacement file proc)
+ "Like 'with-atomic-file-replacement', but PROC is called with a single
+argument---the result of parsing FILE's contents as json---and should a value
+to be written as json to the replacement FILE."
+ (with-atomic-file-replacement file
+ (lambda (in out)
+ (write-json (proc (read-json in)) out))))
+
+(define* (assoc-ref* alist key #:optional default)
+ "Like assoc-ref, but return DEFAULT instead of #f if no value exists."
+ (match (assoc key alist)
+ (#f default)
+ ((_ . value) value)))
+
+(define* (jsobject-ref obj key #:optional default)
+ (match obj
+ (('@ . alist) (assoc-ref* alist key default))))
+
+(define* (alist-pop alist key #:optional (= equal?))
+ "Return two values, the first pair in ALIST with key KEY, and the other
+elements. Equality calls are made as (= KEY ALISTCAR)."
+ (define (found? pair)
+ (= key (car pair)))
+
+ (let ((before after (break found? alist)))
+ (if (pair? after)
+ (values (car after) (append before (cdr after)))
+ (values #f before))))
+
+(define* (alist-update alist key proc #:optional default (= equal?))
+ "Return an association list like ALIST, but with KEY mapped to the result of
+PROC applied to the first value found under the comparison (= KEY ALISTCAR).
+If no such value exists, use DEFAULT instead.
+Unlike acons, this removes the previous association of KEY (assuming it is
+unique), but the result may still share storage with ALIST."
+ (let ((pair rest (alist-pop alist key =)))
+ (acons key
+ (proc (if (pair? pair)
+ (cdr pair)
+ default))
+ rest)))
+
+(define (jsobject-update* js . updates)
+ "Return a json object like JS, but with all UPDATES applied. Each update is
+a list (KEY PROC [DEFAULT]), so that KEY is mapped to the result of PROC
+applied to the value to which KEY is mapped in JS. If no such mapping exists,
+PROC is instead applied to DEFAULT, or to '#f' is no DEFAULT is specified.
+The update takes place from left to right, so later UPDATERs will receive the
+values returned by earlier UPDATERs for the same KEY."
+ (match js
+ (('@ . alist)
+ (let loop ((alist alist)
+ (updates updates))
+ (match updates
+ (() (cons '@ alist))
+ (((key proc) . updates)
+ (loop (alist-update alist key proc #f equal?) updates))
+ (((key proc default) . updates)
+ (loop (alist-update alist key proc default equal?) updates)))))))
+
+(define (jsobject-union combine seed . objects)
+ "Merge OBJECTS into SEED by applying (COMBINE KEY VAL0 VAL), where VAL0
+is the value found in the (possibly updated) SEED and VAL is the new value
+found in one of the OBJECTS."
+ (match seed
+ (('@ . aseed)
+ (match objects
+ (() seed)
+ ((('@ . alists) ...)
+ (cons
+ '@
+ (fold (lambda (alist aseed)
+ (if (null? aseed) alist
+ (fold
+ (match-lambda*
+ (((k . v) aseed)
+ (let ((pair tail (alist-pop alist k)))
+ (match pair
+ (#f (acons k v aseed))
+ ((_ . v0) (acons k (combine k v0 v) aseed))))))
+ aseed
+ alist)))
+ aseed
+ alists)))))))
+
+;; Possibly useful helper functions:
+;; (define (newest key val0 val) val)
+;; (define (unkeyed->keyed proc) (lambda (_key val0 val) (proc val0 val)))
+
+
+;;;
+;;; Phases.
+;;;
(define (set-home . _)
(with-directory-excursion ".."
@@ -49,7 +143,7 @@
(define (module-name module)
(let* ((package.json (string-append module "/package.json"))
(package-meta (call-with-input-file package.json read-json)))
- (assoc-ref package-meta "name")))
+ (jsobject-ref package-meta "name")))
(define (index-modules input-paths)
(define (list-modules directory)
@@ -73,27 +167,58 @@
(define index (index-modules (map cdr inputs)))
- (define (resolve-dependencies package-meta meta-key)
- (fold (lambda (key+value acc)
- (match key+value
- ('@ acc)
- ((key . value) (acons key (hash-ref index key value) acc))))
- '()
- (or (assoc-ref package-meta meta-key) '())))
+ (define resolve-dependencies
+ (match-lambda
+ (('@ . alist)
+ (cons '@ (map (match-lambda
+ ((key . value)
+ (cons key (hash-ref index key value))))
+ alist)))))
- (with-atomic-file-replacement "package.json"
- (lambda (in out)
- (let ((package-meta (read-json in)))
- (assoc-set! package-meta "dependencies"
- (append
- '(@)
- (resolve-dependencies package-meta "dependencies")
- (resolve-dependencies package-meta "peerDependencies")))
- (assoc-set! package-meta "devDependencies"
- (append
- '(@)
- (resolve-dependencies package-meta "devDependencies")))
- (write-json package-meta out))))
+ (with-atomic-json-file-replacement "package.json"
+ (lambda (pkg-meta)
+ (jsobject-update*
+ pkg-meta
+ `("devDependencies" ,resolve-dependencies (@))
+ `("dependencies" ,(lambda (deps)
+ (resolve-dependencies
+ (jsobject-union
+ (lambda (k a b) b)
+ (jsobject-ref pkg-meta "peerDependencies" '(@))
+ deps)))
+ (@)))))
+ #t)
+
+(define (delete-dependencies absent)
+ "Rewrite 'package.json' to allow the build to proceed without packages
+listed in ABSENT, a list of strings naming npm packages.
+
+To prevent the deleted dependencies from being reintroduced, use this function
+only after the 'patch-dependencies' phase."
+ (define delete-from-jsobject
+ (match-lambda
+ (('@ . alist)
+ (cons '@ (filter (match-lambda
+ ((k . _)
+ (not (member k absent))))
+ alist)))))
+
+ (with-atomic-json-file-replacement "package.json"
+ (lambda (pkg-meta)
+ (jsobject-update*
+ pkg-meta
+ `("devDependencies" ,delete-from-jsobject (@))
+ `("dependencies" ,delete-from-jsobject (@))))))
+
+(define* (delete-lockfiles #:key inputs #:allow-other-keys)
+ "Delete 'package-lock.json', 'yarn.lock', and 'npm-shrinkwrap.json', if they
+exist."
+ (for-each (lambda (pth)
+ (when (file-exists? pth)
+ (delete-file pth)))
+ '("package-lock.json"
+ "yarn.lock"
+ "npm-shrinkwrap.json"))
#t)
(define* (configure #:key outputs inputs #:allow-other-keys)
@@ -103,9 +228,7 @@
(define* (build #:key inputs #:allow-other-keys)
(let ((package-meta (call-with-input-file "package.json" read-json)))
- (if (and=> (assoc-ref package-meta "scripts")
- (lambda (scripts)
- (assoc-ref scripts "build")))
+ (if (jsobject-ref (jsobject-ref package-meta "scripts" '(@)) "build" #f)
(let ((npm (string-append (assoc-ref inputs "node") "/bin/npm")))
(invoke npm "run" "build"))
(format #t "there is no build script to run~%"))
@@ -142,15 +265,68 @@
"install" "../package.tgz")
#t))
+(define* (avoid-node-gyp-rebuild #:key outputs #:allow-other-keys)
+ "Adjust the installed 'package.json' to remove an 'install' script that
+would try to run 'node-gyp rebuild'."
+ ;; We want to take advantage of `npm install`'s automatic support for
+ ;; building native addons with node-gyp: in particular, it helps us avoid
+ ;; hard-coding the specifics of how npm's internal copy of node-gyp is
+ ;; currently packaged. However, the mechanism by which the automatic support
+ ;; is implemented causes problems for us.
+ ;;
+ ;; If a package contains a 'binding.gyp' file and does not define an
+ ;; 'install' or 'preinstall' script, 'npm install' runs a default install
+ ;; script consisting of 'node-gyp rebuild'. In our 'install' phase, this
+ ;; implicit 'install' script, if it is applicable, is explicitly added to
+ ;; the "package.json" file. However, if another Guix package were to use a
+ ;; Node.js package with such an 'install' script, the dependent package's
+ ;; build process would fail, because 'node-gyp rebuild' would try to write
+ ;; to the store.
+ ;;
+ ;; Here, if the installed "package.json" defines scripts.install as
+ ;; "node-gyp rebuild", we replace it with a no-op. Importantly, deleting the
+ ;; install script definition would not be enough, because the default
+ ;; install script would cause the same problem.
+ ;;
+ ;; For further details, see:
+ ;; - https://docs.npmjs.com/cli/v8/configuring-npm/package-json#default-values
+ ;; - https://docs.npmjs.com/cli/v8/using-npm/scripts#best-practices
+ (define installed-package.json
+ (search-input-file outputs (string-append "/lib/node_modules/"
+ (module-name ".")
+ "/package.json")))
+ ;; We don't want to use an atomic replacement here, because we often don't
+ ;; even need to overwrite this file. Therefore, let's use some helpers
+ ;; that we'd otherwise not need.
+ (define pkg-meta
+ (call-with-input-file installed-package.json read-json))
+ (define scripts
+ (jsobject-ref pkg-meta "scripts" '(@)))
+ (define (jsobject-set js key val)
+ (jsobject-update* js (list key (const val))))
+
+ (when (equal? "node-gyp rebuild" (jsobject-ref scripts "install" #f))
+ (call-with-output-file installed-package.json
+ (lambda (out)
+ (write-json
+ (jsobject-set pkg-meta
+ "scripts"
+ (jsobject-set scripts
+ "install"
+ "echo Guix: avoiding node-gyp rebuild"))
+ out)))))
+
(define %standard-phases
(modify-phases gnu:%standard-phases
(add-after 'unpack 'set-home set-home)
(add-before 'configure 'patch-dependencies patch-dependencies)
+ (add-after 'patch-dependencies 'delete-lockfiles delete-lockfiles)
(replace 'configure configure)
(replace 'build build)
(replace 'check check)
(add-before 'install 'repack repack)
- (replace 'install install)))
+ (replace 'install install)
+ (add-after 'install 'avoid-node-gyp-rebuild avoid-node-gyp-rebuild)))
(define* (node-build #:key inputs (phases %standard-phases)
#:allow-other-keys #:rest args)
diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm
index 45f95c509d..a7401fd73f 100644
--- a/guix/build/syscalls.scm
+++ b/guix/build/syscalls.scm
@@ -132,6 +132,7 @@
CLONE_CHILD_CLEARTID
CLONE_CHILD_SETTID
+ CLONE_NEWCGROUP
CLONE_NEWNS
CLONE_NEWUTS
CLONE_NEWIPC
@@ -1025,6 +1026,7 @@ caller lacks root privileges."
;; Linux clone flags, from linux/sched.h
(define CLONE_CHILD_CLEARTID #x00200000)
(define CLONE_CHILD_SETTID #x01000000)
+(define CLONE_NEWCGROUP #x02000000)
(define CLONE_NEWNS #x00020000)
(define CLONE_NEWUTS #x04000000)
(define CLONE_NEWIPC #x08000000)
diff --git a/guix/build/utils.scm b/guix/build/utils.scm
index 39e581b0fa..b822caf619 100644
--- a/guix/build/utils.scm
+++ b/guix/build/utils.scm
@@ -8,6 +8,7 @@
;;; Copyright © 2020 Efraim Flashner <efraim@flashner.co.il>
;;; Copyright © 2020, 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;; Copyright © 2021 Brendan Tildesley <mail@brendan.scot>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -1473,10 +1474,9 @@ not supported."
`(let ((cl (command-line)))
(apply execl ,interpreter
(car cl)
- (cons (car cl)
- (append
- ',(string-split args #\space)
- cl))))))
+ (append
+ ',(string-tokenize args char-set:graphic)
+ cl)))))
(template (string-append prog ".XXXXXX"))
(out (mkstemp! template))
(st (stat prog))
diff --git a/guix/channels.scm b/guix/channels.scm
index e4e0428eb5..5f47834c10 100644
--- a/guix/channels.scm
+++ b/guix/channels.scm
@@ -2,6 +2,7 @@
;;; Copyright © 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2019 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;; Copyright © 2021 Brice Waegeneire <brice@waegenei.re>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -1009,6 +1010,7 @@ true, include its introduction, if any."
`(channel
(name ',(channel-name channel))
(url ,(channel-url channel))
+ (branch ,(channel-branch channel))
(commit ,(channel-commit channel))
,@(if intro
`((introduction (make-channel-introduction
diff --git a/guix/ci.scm b/guix/ci.scm
index 01b493b3af..88b80f781d 100644
--- a/guix/ci.scm
+++ b/guix/ci.scm
@@ -208,7 +208,7 @@ api-agnostic."
(map json->build (vector->list queue))))
(define* (latest-builds url #:optional (limit %query-limit)
- #:key evaluation system job status)
+ #:key evaluation system job jobset status)
"Return the latest builds performed by the CI server at URL. If EVALUATION
is an integer, restrict to builds of EVALUATION. If SYSTEM is true (a system
string such as \"x86_64-linux\"), restrict to builds for SYSTEM."
@@ -218,6 +218,7 @@ string such as \"x86_64-linux\"), restrict to builds for SYSTEM."
`("evaluation" ,evaluation)
`("system" ,system)
`("job" ,job)
+ `("jobset" ,jobset)
`("status" ,status))))
;; Note: Hydra does not provide a "derivation" field for entries in
;; 'latestbuilds', but Cuirass does.
@@ -286,6 +287,7 @@ definitions at URL. Return false if no commit were found."
(let* ((job-name (string-append "guix." (%current-system)))
(build (match (latest-builds url 1
#:job job-name
+ #:jobset "guix"
#:status 0) ;success
((build) build)
(_ #f)))
diff --git a/guix/combinators.scm b/guix/combinators.scm
index 88ad09dbe6..261d6bb57e 100644
--- a/guix/combinators.scm
+++ b/guix/combinators.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012-2017, 2021 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org>
;;; Copyright © 2020 Arun Isaac <arunisaac@systemreboot.net>
;;;
@@ -24,7 +24,9 @@
#:export (fold2
fold-tree
fold-tree-leaves
- compile-time-value))
+ compile-time-value
+ procedure-call-location
+ define-compile-time-procedure))
;;; Commentary:
;;;
@@ -100,4 +102,48 @@ evaluate to a simple datum."
(_ #`'#,(datum->syntax s val)))))))
v))))
+(define-syntax-parameter procedure-call-location
+ (lambda (s)
+ (syntax-violation 'procedure-call-location
+ "'procedure-call-location' may only be used \
+within 'define-compile-time-procedure'"
+ s)))
+
+(define-syntax-rule (define-compile-time-procedure (proc (arg pred) ...)
+ body ...)
+ "Define PROC as a macro such that, if every actual argument in a \"call\"
+matches PRED, then BODY is evaluated at macro-expansion time. BODY must
+return a single value in a type that has read syntax--e.g., numbers, strings,
+lists, etc.
+
+BODY can refer to 'procedure-call-location', which is bound to a source
+property alist corresponding to the call site.
+
+This macro is meant to be used primarily for small procedures that validate or
+process its arguments in a way that may be equally well performed at
+macro-expansion time."
+ (define-syntax proc
+ (lambda (s)
+ (define loc
+ #`(identifier-syntax
+ '#,(datum->syntax #'s (syntax-source s))))
+
+ (syntax-case s ()
+ ((_ arg ...)
+ (and (pred (syntax->datum #'arg)) ...)
+ (let ((arg (syntax->datum #'arg)) ...)
+ (syntax-parameterize ((procedure-call-location
+ (identifier-syntax (syntax-source s))))
+ body ...)))
+ ((_ actual (... ...))
+ #`((lambda (arg ...)
+ (syntax-parameterize ((procedure-call-location #,loc))
+ body ...))
+ actual (... ...)))
+ (id
+ (identifier? #'id)
+ #`(lambda (arg ...)
+ (syntax-parameterize ((procedure-call-location #,loc))
+ body ...)))))))
+
;;; combinators.scm ends here
diff --git a/guix/cpu.scm b/guix/cpu.scm
new file mode 100644
index 0000000000..e1911f52a8
--- /dev/null
+++ b/guix/cpu.scm
@@ -0,0 +1,143 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Ludovic Courtès <ludo@gnu.org>
+;;;
+;;; 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 cpu)
+ #:use-module (guix sets)
+ #:use-module (guix memoization)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-9)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 rdelim)
+ #:export (current-cpu
+ cpu?
+ cpu-architecture
+ cpu-family
+ cpu-model
+ cpu-flags
+
+ cpu->gcc-architecture))
+
+;;; Commentary:
+;;;
+;;; This module provides tools to determine the micro-architecture supported
+;;; by the CPU and to map it to a name known to GCC's '-march'.
+;;;
+;;; Code:
+
+;; CPU description.
+(define-record-type <cpu>
+ (cpu architecture family model flags)
+ cpu?
+ (architecture cpu-architecture) ;string, from 'uname'
+ (family cpu-family) ;integer
+ (model cpu-model) ;integer
+ (flags cpu-flags)) ;set of strings
+
+(define current-cpu
+ (mlambda ()
+ "Return a <cpu> record representing the host CPU."
+ (define (prefix? prefix)
+ (lambda (str)
+ (string-prefix? prefix str)))
+
+ (call-with-input-file "/proc/cpuinfo"
+ (lambda (port)
+ (let loop ((family #f)
+ (model #f))
+ (match (read-line port)
+ ((? eof-object?)
+ #f)
+ ((? (prefix? "cpu family") str)
+ (match (string-tokenize str)
+ (("cpu" "family" ":" family)
+ (loop (string->number family) model))))
+ ((? (prefix? "model") str)
+ (match (string-tokenize str)
+ (("model" ":" model)
+ (loop family (string->number model)))
+ (_
+ (loop family model))))
+ ((? (prefix? "flags") str)
+ (match (string-tokenize str)
+ (("flags" ":" flags ...)
+ (cpu (utsname:machine (uname))
+ family model (list->set flags)))))
+ (_
+ (loop family model))))))))
+
+(define (cpu->gcc-architecture cpu)
+ "Return the architecture name, suitable for GCC's '-march' flag, that
+corresponds to CPU, a record as returned by 'current-cpu'."
+ (match (cpu-architecture cpu)
+ ("x86_64"
+ ;; Transcribed from GCC's 'host_detect_local_cpu' in driver-i386.c.
+ (or (and (= 6 (cpu-family cpu)) ;the "Pentium Pro" family
+ (letrec-syntax ((model (syntax-rules (=>)
+ ((_) #f)
+ ((_ (candidate => integers ...) rest
+ ...)
+ (or (and (= (cpu-model cpu) integers)
+ candidate)
+ ...
+ (model rest ...))))))
+ (model ("bonnel" => #x1c #x26)
+ ("silvermont" => #x37 #x4a #x4d #x5a #x5d)
+ ("core2" => #x0f #x17 #x1d)
+ ("nehalem" => #x1a #x1e #x1f #x2e)
+ ("westmere" => #x25 #x2c #x2f)
+ ("sandybridge" => #x2a #x2d)
+ ("ivybridge" => #x3a #x3e)
+ ("haswell" => #x3c #x3f #x45 #x46)
+ ("broadwell" => #x3d #x47 #x4f #x56)
+ ("skylake" => #x4e #x5e #x8e #x9e)
+ ("skylake-avx512" => #x55) ;TODO: cascadelake
+ ("knl" => #x57)
+ ("cannonlake" => #x66)
+ ("knm" => #x85))))
+
+ ;; Fallback case for non-Intel processors or for Intel processors not
+ ;; recognized above.
+ (letrec-syntax ((if-flags (syntax-rules (=>)
+ ((_)
+ #f)
+ ((_ (flags ... => name) rest ...)
+ (if (every (lambda (flag)
+ (set-contains? (cpu-flags cpu)
+ flag))
+ '(flags ...))
+ name
+ (if-flags rest ...))))))
+ (if-flags ("avx512" => "knl")
+ ("adx" => "broadwell")
+ ("avx2" => "haswell")
+ ;; TODO: tigerlake, cooperlake, etc.
+ ("avx" => "sandybridge")
+ ("sse4_2" "gfni" => "tremont")
+ ("sse4_2" "sgx" => "goldmont-plus")
+ ("sse4_2" "xsave" => "goldmont")
+ ("sse4_2" "movbe" => "silvermont")
+ ("sse4_2" => "nehalem")
+ ("ssse3" "movbe" => "bonnell")
+ ("ssse3" => "core2")))
+
+ ;; TODO: Recognize AMD models (bdver*, znver*, etc.)?
+
+ "x86_64"))
+ (architecture
+ ;; TODO: AArch64.
+ architecture)))
diff --git a/guix/git.scm b/guix/git.scm
index dc2ca1be84..43e85a5026 100644
--- a/guix/git.scm
+++ b/guix/git.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2021 Kyle Meyer <kyle@kyleam.com>
;;; Copyright © 2021 Marius Bakke <marius@gnu.org>
+;;; Copyright © 2022 Maxime Devos <maximedevos@telenet.be>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -33,6 +34,8 @@
#:use-module (guix utils)
#:use-module (guix records)
#:use-module (guix gexp)
+ #:autoload (guix git-download)
+ (git-reference-url git-reference-commit git-reference-recursive?)
#:use-module (guix sets)
#:use-module ((guix diagnostics) #:select (leave warning))
#:use-module (guix progress)
@@ -65,7 +68,9 @@
git-checkout-url
git-checkout-branch
git-checkout-commit
- git-checkout-recursive?))
+ git-checkout-recursive?
+
+ git-reference->git-checkout))
(define %repository-cache-directory
(make-parameter (string-append (cache-directory #:ensure? #f)
@@ -672,6 +677,13 @@ is true, limit to only refs/tags."
(commit git-checkout-commit (default #f)) ;#f | tag | commit
(recursive? git-checkout-recursive? (default #f)))
+(define (git-reference->git-checkout reference)
+ "Convert the <git-reference> REFERENCE to an equivalent <git-checkout>."
+ (git-checkout
+ (url (git-reference-url reference))
+ (commit (git-reference-commit reference))
+ (recursive? (git-reference-recursive? reference))))
+
(define* (latest-repository-commit* url #:key ref recursive? log-port)
;; Monadic variant of 'latest-repository-commit'.
(lambda (store)
diff --git a/guix/hash.scm b/guix/hash.scm
new file mode 100644
index 0000000000..3cb68e5c44
--- /dev/null
+++ b/guix/hash.scm
@@ -0,0 +1,73 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
+;;; Copyright © 2022 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; 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 hash)
+ #:use-module (gcrypt hash)
+ #:use-module (guix serialization)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-11)
+ #:export (vcs-file?
+ file-hash*))
+
+(define (vcs-file? file stat)
+ "Returns true if FILE is a version control system file."
+ (case (stat:type stat)
+ ((directory)
+ (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
+ ((regular)
+ ;; Git sub-modules have a '.git' file that is a regular text file.
+ (string=? (basename file) ".git"))
+ (else
+ #f)))
+
+(define* (file-hash* file #:key
+ (algorithm (hash-algorithm sha256))
+ (recursive? 'auto)
+ (select? (negate vcs-file?)))
+ "Compute the hash of FILE with ALGORITHM.
+
+Symbolic links are only dereferenced if RECURSIVE? is false.
+Directories are only supported if RECURSIVE? is #true or 'auto'.
+The executable bit is only recorded if RECURSIVE? is #true.
+If FILE is a symbolic link, it is only followed if RECURSIVE? is false.
+
+For regular files, there are two different hashes when the executable
+hash isn't recorded: the regular hash and the nar hash. In most situations,
+the regular hash is desired and setting RECURSIVE? to 'auto' does the right
+thing for both regular files and directories.
+
+This procedure must only be used under controlled circumstances;
+the detection of symbolic links in FILE is racy.
+
+When FILE is a directory, the procedure SELECT? called as (SELECT? FILE STAT)
+decides which files to include. By default, version control files are
+excluded. To include everything, SELECT? can be set to (const #true)."
+ (if (or (eq? recursive? #true)
+ (and (eq? recursive? 'auto)
+ ;; Don't change this to (eq? 'directory ...), because otherwise
+ ;; if 'file' denotes a symbolic link, the 'file-hash' below
+ ;; would dereference it -- dereferencing symbolic links would
+ ;; open an avoidable can of potential worms.
+ (not (eq? 'regular (stat:type (lstat file))))))
+ (let-values (((port get-hash)
+ (open-hash-port algorithm)))
+ (write-file file port #:select? select?)
+ (force-output port)
+ (get-hash))
+ (file-hash algorithm file)))
diff --git a/guix/import/cran.scm b/guix/import/cran.scm
index 1389576cad..7a73c11382 100644
--- a/guix/import/cran.scm
+++ b/guix/import/cran.scm
@@ -1,8 +1,9 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2015, 2016, 2017, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2020 Martin Becze <mjbecze@riseup.net>
+;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -35,10 +36,9 @@
#:use-module (guix memoization)
#:use-module (guix http-client)
#:use-module (guix diagnostics)
+ #:use-module (guix hash)
#:use-module (guix i18n)
- #:use-module (gcrypt hash)
#:use-module (guix store)
- #:use-module ((guix serialization) #:select (write-file))
#:use-module (guix base32)
#:use-module ((guix download) #:select (download-to-store))
#:use-module (guix import utils)
@@ -196,17 +196,6 @@ bioconductor package NAME, or #F if the package is unknown."
(bioconductor-packages-list type))
(cut assoc-ref <> "Version")))
-;; XXX taken from (guix scripts hash)
-(define (vcs-file? file stat)
- (case (stat:type stat)
- ((directory)
- (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
- ((regular)
- ;; Git sub-modules have a '.git' file that is a regular text file.
- (string=? (basename file) ".git"))
- (else
- #f)))
-
;; Little helper to download URLs only once.
(define download
(memoize
@@ -464,16 +453,6 @@ reference the pkg-config tool."
(define (needs-knitr? meta)
(member "knitr" (listify meta "VignetteBuilder")))
-;; XXX adapted from (guix scripts hash)
-(define (file-hash file select? recursive?)
- ;; Compute the hash of FILE.
- (if recursive?
- (let-values (((port get-hash) (open-sha256-port)))
- (write-file file port #:select? select?)
- (force-output port)
- (get-hash))
- (call-with-input-file file port-sha256)))
-
(define (description->package repository meta)
"Return the `package' s-expression for an R package published on REPOSITORY
from the alist META, which was derived from the R package's DESCRIPTION file."
@@ -514,8 +493,8 @@ from the alist META, which was derived from the R package's DESCRIPTION file."
((urls ...) urls)
((? string? url) url)
(_ #f)))))
- (git? (assoc-ref meta 'git))
- (hg? (assoc-ref meta 'hg))
+ (git? (if (assoc-ref meta 'git) #true #false))
+ (hg? (if (assoc-ref meta 'hg) #true #false))
(source (download source-url #:method (cond
(git? 'git)
(hg? 'hg)
@@ -571,12 +550,7 @@ from the alist META, which was derived from the R package's DESCRIPTION file."
(sha256
(base32
,(bytevector->nix-base32-string
- (case repository
- ((git)
- (file-hash source (negate vcs-file?) #t))
- ((hg)
- (file-hash source (negate vcs-file?) #t))
- (else (file-sha256 source))))))))
+ (file-hash* source #:recursive? (or git? hg?)))))))
,@(if (not (and git? hg?
(equal? (string-append "r-" name)
(cran-guix-name name))))
diff --git a/guix/import/elpa.scm b/guix/import/elpa.scm
index edabb88b7a..ea77a7c244 100644
--- a/guix/import/elpa.scm
+++ b/guix/import/elpa.scm
@@ -5,6 +5,7 @@
;;; Copyright © 2020 Martin Becze <mjbecze@riseup.net>
;;; Copyright © 2020 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
+;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -37,13 +38,14 @@
#:use-module (guix import utils)
#:use-module (guix http-client)
#:use-module (guix git)
+ #:use-module (guix hash)
#:use-module ((guix serialization) #:select (write-file))
#:use-module (guix store)
#:use-module (guix ui)
- #:use-module (gcrypt hash)
#:use-module (guix base32)
#:use-module (guix upstream)
#:use-module (guix packages)
+ #:use-module (guix memoization)
#:use-module ((guix utils) #:select (call-with-temporary-output-file))
#:export (elpa->guix-package
guix-package->elpa-name
@@ -229,27 +231,6 @@ keywords to values."
(close-port port)
(data->recipe (cons ':name data))))
-;; XXX adapted from (guix scripts hash)
-(define (file-hash file select? recursive?)
- ;; Compute the hash of FILE.
- (if recursive?
- (let-values (((port get-hash) (open-sha256-port)))
- (write-file file port #:select? select?)
- (force-output port)
- (get-hash))
- (call-with-input-file file port-sha256)))
-
-;; XXX taken from (guix scripts hash)
-(define (vcs-file? file stat)
- (case (stat:type stat)
- ((directory)
- (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
- ((regular)
- ;; Git sub-modules have a '.git' file that is a regular text file.
- (string=? (basename file) ".git"))
- (else
- #f)))
-
(define (git-repository->origin recipe url)
"Fetch origin details from the Git repository at URL for the provided MELPA
RECIPE."
@@ -271,7 +252,7 @@ RECIPE."
(sha256
(base32
,(bytevector->nix-base32-string
- (file-hash directory (negate vcs-file?) #t)))))))
+ (file-hash* directory #:recursive? #true)))))))
(define* (melpa-recipe->origin recipe)
"Fetch origin details from the MELPA recipe and associated repository for
@@ -380,7 +361,8 @@ type '<elpa-package>'."
(sha256
(base32
,(if tarball
- (bytevector->nix-base32-string (file-sha256 tarball))
+ (bytevector->nix-base32-string
+ (file-hash* tarball #:recursive? #false))
"failed to download package")))))))
(build-system emacs-build-system)
,@(maybe-inputs 'propagated-inputs dependencies)
@@ -424,7 +406,7 @@ type '<elpa-package>'."
(define (latest-release package)
"Return an <upstream-release> for the latest release of PACKAGE."
(define name (guix-package->elpa-name package))
- (define repo 'gnu)
+ (define repo (elpa-repository package))
(match (elpa-package-info name repo)
(#f
@@ -443,11 +425,20 @@ type '<elpa-package>'."
(urls (list url))
(signature-urls (list (string-append url ".sig"))))))))
-(define package-from-gnu.org?
- (url-predicate (lambda (url)
- (let ((uri (string->uri url)))
- (and uri
- (string=? (uri-host uri) "elpa.gnu.org"))))))
+(define elpa-repository
+ (memoize
+ (url-predicate (lambda (url)
+ (let ((uri (string->uri url)))
+ (and uri
+ (cond
+ ((string=? (uri-host uri) "elpa.gnu.org")
+ 'gnu)
+ ((string=? (uri-host uri) "elpa.nongnu.org")
+ 'nongnu)
+ (else #f))))))))
+
+(define (package-from-elpa-repository? package)
+ (member (elpa-repository package) '(gnu nongnu)))
(define %elpa-updater
;; The ELPA updater. We restrict it to packages hosted on elpa.gnu.org
@@ -455,7 +446,7 @@ type '<elpa-package>'."
(upstream-updater
(name 'elpa)
(description "Updater for ELPA packages")
- (pred package-from-gnu.org?)
+ (pred package-from-elpa-repository?)
(latest latest-release)))
(define elpa-guix-name (cut guix-name "emacs-" <>))
diff --git a/guix/import/git.scm b/guix/import/git.scm
index 1eb219f3fe..4cf404677c 100644
--- a/guix/import/git.scm
+++ b/guix/import/git.scm
@@ -1,6 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
+;;; Copyright © 2022 Maxime Devos <maximedevos@telenet.be>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -34,6 +35,7 @@
#:use-module (srfi srfi-26)
#:use-module (srfi srfi-34)
#:use-module (srfi srfi-35)
+ #:use-module (srfi srfi-71)
#:export (%generic-git-updater
;; For tests.
@@ -172,21 +174,21 @@ repository at URL."
(values version tag)))))))
(define (latest-git-tag-version package)
- "Given a PACKAGE, return the latest version of it, or #f if the latest version
-could not be determined."
+ "Given a PACKAGE, return the latest version of it and the corresponding git
+tag, or #false and #false if the latest version could not be determined."
(guard (c ((or (git-no-tags-error? c) (git-no-valid-tags-error? c))
(warning (or (package-field-location package 'source)
(package-location package))
(G_ "~a for ~a~%")
(condition-message c)
(package-name package))
- #f)
+ (values #f #f))
((eq? (exception-kind c) 'git-error)
(warning (or (package-field-location package 'source)
(package-location package))
(G_ "failed to fetch Git repository for ~a~%")
(package-name package))
- #f))
+ (values #f #f)))
(let* ((source (package-source package))
(url (git-reference-url (origin-uri source)))
(property (cute assq-ref (package-properties package) <>)))
@@ -208,14 +210,16 @@ could not be determined."
"Return an <upstream-source> for the latest release of PACKAGE."
(let* ((name (package-name package))
(old-version (package-version package))
- (url (git-reference-url (origin-uri (package-source package))))
- (new-version (latest-git-tag-version package)))
-
- (and new-version
+ (old-reference (origin-uri (package-source package)))
+ (new-version new-version-tag (latest-git-tag-version package)))
+ (and new-version new-version-tag
(upstream-source
(package name)
(version new-version)
- (urls (list url))))))
+ (urls (git-reference
+ (url (git-reference-url old-reference))
+ (commit new-version-tag)
+ (recursive? (git-reference-recursive? old-reference))))))))
(define %generic-git-updater
(upstream-updater
diff --git a/guix/import/github.scm b/guix/import/github.scm
index 888b148ffb..8c1898c0c5 100644
--- a/guix/import/github.scm
+++ b/guix/import/github.scm
@@ -4,6 +4,7 @@
;;; Copyright © 2018 Eric Bavier <bavier@member.fsf.org>
;;; Copyright © 2019 Arun Isaac <arunisaac@systemreboot.net>
;;; Copyright © 2019 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2022 Maxime Devos <maximedevos@telenet.be>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -25,6 +26,7 @@
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-26)
#:use-module (srfi srfi-34)
+ #:use-module (srfi srfi-71)
#:use-module (guix utils)
#:use-module (guix i18n)
#:use-module (guix diagnostics)
@@ -37,7 +39,10 @@
#:use-module (guix upstream)
#:use-module (guix http-client)
#:use-module (web uri)
- #:export (%github-updater))
+ #:export (%github-api %github-updater))
+
+;; For tests.
+(define %github-api (make-parameter "https://api.github.com"))
(define (find-extension url)
"Return the extension of the archive e.g. '.tar.gz' given a URL, or
@@ -148,11 +153,11 @@ tags show up in the \"Releases\" tab of the web UI. For instance,
'https://api.github.com/repos/aconchillo/guile-json/releases' returns the
empty list."
(define release-url
- (string-append "https://api.github.com/repos/"
+ (string-append (%github-api) "/repos/"
(github-user-slash-repository url)
"/releases"))
(define tag-url
- (string-append "https://api.github.com/repos/"
+ (string-append (%github-api) "/repos/"
(github-user-slash-repository url)
"/tags"))
@@ -181,12 +186,15 @@ empty list."
(x x)))))
(define (latest-released-version url package-name)
- "Return a string of the newest released version name given a string URL like
+ "Return the newest released version and its tag given a string URL like
'https://github.com/arq5x/bedtools2/archive/v2.24.0.tar.gz' and the name of
-the package e.g. 'bedtools2'. Return #f if there is no releases"
+the package e.g. 'bedtools2'. Return #f (two values) if there are no
+releases."
(define (pre-release? x)
(assoc-ref x "prerelease"))
+ ;; This procedure returns (version . tag) pair, or #f
+ ;; if RELEASE doesn't seyem to correspond to a version.
(define (release->version release)
(let ((tag (or (assoc-ref release "tag_name") ;a "release"
(assoc-ref release "name"))) ;a tag
@@ -197,22 +205,22 @@ the package e.g. 'bedtools2'. Return #f if there is no releases"
((and (< name-length (string-length tag))
(string=? (string-append package-name "-")
(substring tag 0 (+ name-length 1))))
- (substring tag (+ name-length 1)))
+ (cons (substring tag (+ name-length 1)) tag))
;; some tags start with a "v" e.g. "v0.25.0"
;; or with the word "version" e.g. "version.2.1"
;; where some are just the version number
((string-prefix? "version" tag)
- (if (char-set-contains? char-set:digit (string-ref tag 7))
- (substring tag 7)
- (substring tag 8)))
+ (cons (if (char-set-contains? char-set:digit (string-ref tag 7))
+ (substring tag 7)
+ (substring tag 8)) tag))
((string-prefix? "v" tag)
- (substring tag 1))
+ (cons (substring tag 1) tag))
;; Finally, reject tags that don't start with a digit:
;; they may not represent a release.
((and (not (string-null? tag))
(char-set-contains? char-set:digit
(string-ref tag 0)))
- tag)
+ (cons tag tag))
(else #f))))
(let* ((json (and=> (fetch-releases-or-tags url)
@@ -229,14 +237,14 @@ https://github.com/settings/tokens"))
(match (remove pre-release? json)
(() json) ; keep everything
(releases releases)))
- version>?)
- ((latest-release . _) latest-release)
- (() #f)))))
+ (lambda (x y) (version>? (car x) (car y))))
+ (((latest-version . tag) . _) (values latest-version tag))
+ (() (values #f #f))))))
(define (latest-release pkg)
"Return an <upstream-source> for the latest release of PKG."
- (define (origin-github-uri origin)
- (match (origin-uri origin)
+ (define (github-uri uri)
+ (match uri
((? string? url)
url) ;surely a github.com URL
((? download:git-reference? ref)
@@ -244,14 +252,20 @@ https://github.com/settings/tokens"))
((urls ...)
(find (cut string-contains <> "github.com") urls))))
- (let* ((source-uri (origin-github-uri (package-source pkg)))
+ (let* ((original-uri (origin-uri (package-source pkg)))
+ (source-uri (github-uri original-uri))
(name (package-name pkg))
- (newest-version (latest-released-version source-uri name)))
+ (newest-version version-tag
+ (latest-released-version source-uri name)))
(if newest-version
(upstream-source
(package name)
(version newest-version)
- (urls (list (updated-github-url pkg newest-version))))
+ (urls (if (download:git-reference? original-uri)
+ (download:git-reference
+ (inherit original-uri)
+ (commit version-tag))
+ (list (updated-github-url pkg newest-version)))))
#f))) ; On GitHub but no proper releases
(define %github-updater
diff --git a/guix/import/go.scm b/guix/import/go.scm
index 26dbc34b63..d00c13475a 100644
--- a/guix/import/go.scm
+++ b/guix/import/go.scm
@@ -3,7 +3,7 @@
;;; Copyright © 2020 Helio Machado <0x2b3bfa0+guix@googlemail.com>
;;; Copyright © 2021 François Joulaud <francois.joulaud@radiofrance.com>
;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
-;;; Copyright © 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2021-2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
;;; Copyright © 2021 Simon Tournier <zimon.toutoune@gmail.com>
@@ -26,6 +26,7 @@
(define-module (guix import go)
#:use-module (guix build-system go)
#:use-module (guix git)
+ #:use-module (guix hash)
#:use-module (guix i18n)
#:use-module (guix diagnostics)
#:use-module (guix import utils)
@@ -36,11 +37,11 @@
#:use-module ((guix licenses) #:prefix license:)
#:use-module (guix memoization)
#:autoload (htmlprag) (html->sxml) ;from Guile-Lib
- #:autoload (guix git) (update-cached-checkout)
- #:autoload (gcrypt hash) (open-hash-port hash-algorithm sha256)
#:autoload (guix serialization) (write-file)
#:autoload (guix base32) (bytevector->nix-base32-string)
#:autoload (guix build utils) (mkdir-p)
+ #:autoload (gcrypt hash) (hash-algorithm sha256)
+ #:use-module (ice-9 format)
#:use-module (ice-9 match)
#:use-module (ice-9 peg)
#:use-module (ice-9 rdelim)
@@ -54,6 +55,7 @@
#:use-module (srfi srfi-11)
#:use-module (srfi srfi-26)
#:use-module (srfi srfi-34)
+ #:use-module (srfi srfi-35)
#:use-module (sxml match)
#:use-module ((sxml xpath) #:renamer (lambda (s)
(if (eq? 'filter s)
@@ -499,25 +501,6 @@ source."
goproxy
(module-meta-repo-root meta-data)))
-;; XXX: Copied from (guix scripts hash).
-(define (vcs-file? file stat)
- (case (stat:type stat)
- ((directory)
- (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
- ((regular)
- ;; Git sub-modules have a '.git' file that is a regular text file.
- (string=? (basename file) ".git"))
- (else
- #f)))
-
-;; XXX: Adapted from 'file-hash' in (guix scripts hash).
-(define* (file-hash file #:optional (algorithm (hash-algorithm sha256)))
- ;; Compute the hash of FILE.
- (let-values (((port get-hash) (open-hash-port algorithm)))
- (write-file file port #:select? (negate vcs-file?))
- (force-output port)
- (get-hash)))
-
(define* (git-checkout-hash url reference algorithm)
"Return the ALGORITHM hash of the checkout of URL at REFERENCE, a commit or
tag."
@@ -536,7 +519,7 @@ tag."
(update-cached-checkout url
#:ref
`(tag-or-commit . ,reference)))))
- (file-hash checkout algorithm)))
+ (file-hash* checkout #:algorithm algorithm #:recursive? #true)))
(define (vcs->origin vcs-type vcs-repo-url version)
"Generate the `origin' block of a package depending on what type of source
@@ -588,6 +571,34 @@ control system is being used."
(formatted-message (G_ "unsupported vcs type '~a' for package '~a'")
vcs-type vcs-repo-url)))))
+(define (strip-v-prefix version)
+ "Strip from VERSION the \"v\" prefix that Go uses."
+ (string-trim version #\v))
+
+(define (ensure-v-prefix version)
+ "Add a \"v\" prefix to VERSION if it does not already have one."
+ (if (string-prefix? "v" version)
+ version
+ (string-append "v" version)))
+
+(define (validate-version version available-versions module-path)
+ "Raise an error if VERSION is not among AVAILABLE-VERSIONS, unless VERSION
+is a pseudo-version. Return VERSION."
+ ;; Pseudo-versions do not appear in the versions list; skip the
+ ;; following check.
+ (if (or (go-pseudo-version? version)
+ (member version available-versions))
+ version
+ (raise
+ (make-compound-condition
+ (formatted-message (G_ "version ~a of ~a is not available~%")
+ version module-path available-versions)
+ (condition (&fix-hint
+ (hint (format #f (G_ "Pick one of the following \
+available versions:~{ ~a~}.")
+ (map strip-v-prefix
+ available-versions)))))))))
+
(define* (go-module->guix-package module-path #:key
(goproxy "https://proxy.golang.org")
version
@@ -596,17 +607,11 @@ control system is being used."
The meta-data is fetched from the GOPROXY server and https://pkg.go.dev/.
When VERSION is unspecified, the latest version available is used."
(let* ((available-versions (go-module-available-versions goproxy module-path))
- (version* (or version
- (go-module-version-string goproxy module-path))) ;latest
- ;; Elide the "v" prefix Go uses.
- (strip-v-prefix (cut string-trim <> #\v))
- ;; Pseudo-versions do not appear in the versions list; skip the
- ;; following check.
- (_ (unless (or (go-pseudo-version? version*)
- (member version* available-versions))
- (error (format #f "error: version ~s is not available
-hint: use one of the following available versions ~a\n"
- version* available-versions))))
+ (version* (validate-version
+ (or (and version (ensure-v-prefix version))
+ (go-module-version-string goproxy module-path)) ;latest
+ available-versions
+ module-path))
(content (fetch-go.mod goproxy module-path version*))
(dependencies+versions (go.mod-requirements (parse-go.mod content)))
(dependencies (if pin-versions?
@@ -647,10 +652,10 @@ hint: use one of the following available versions ~a\n"
(synopsis ,synopsis)
(description ,(and=> description beautify-description))
(license ,(match (list->licenses licenses)
- (() #f) ;unknown license
- ((license) ;a single license
+ (() #f) ;unknown license
+ ((license) ;a single license
license)
- ((license ...) ;a list of licenses
+ ((license ...) ;a list of licenses
`(list ,@license)))))
(if pin-versions?
dependencies+versions
@@ -670,12 +675,6 @@ This package and its dependencies won't be imported.~%")
(uri->string (http-get-error-uri c))
(http-get-error-code c)
(http-get-error-reason c))
- (values #f '()))
- (else
- (warning (G_ "Failed to import package ~s.
-reason: ~s.~%")
- package-name
- (exception-args c))
(values #f '())))
(apply go-module->guix-package args)))))
diff --git a/guix/import/minetest.scm b/guix/import/minetest.scm
index abddd885ee..3b2cdcdcac 100644
--- a/guix/import/minetest.scm
+++ b/guix/import/minetest.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;; Copyright © 2021, 2022 Maxime Devos <maximedevos@telenet.be>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -39,6 +39,7 @@
#:use-module (guix base32)
#:use-module (guix git)
#:use-module ((guix git-download) #:prefix download:)
+ #:use-module (guix hash)
#:use-module (guix store)
#:export (%default-sort-key
%contentdb-api
@@ -286,14 +287,6 @@ results. The return value is a list of <package-keys> records."
(with-store store
(latest-repository-commit store url #:ref ref)))
-;; XXX adapted from (guix scripts hash)
-(define (file-hash file)
- "Compute the hash of FILE."
- (let-values (((port get-hash) (open-sha256-port)))
- (write-file file port)
- (force-output port)
- (get-hash)))
-
(define (make-minetest-sexp author/name version repository commit
inputs home-page synopsis
description media-license license)
@@ -314,9 +307,13 @@ MEDIA-LICENSE and LICENSE."
;; The git commit is not always available.
,(and commit
(bytevector->nix-base32-string
- (file-hash
+ (file-hash*
(download-git-repository repository
- `(commit . ,commit)))))))
+ `(commit . ,commit))
+ ;; 'download-git-repository' already filtered out the '.git'
+ ;; directory.
+ #:select? (const #true)
+ #:recursive? #true)))))
(file-name (git-file-name name version))))
(build-system minetest-mod-build-system)
,@(maybe-propagated-inputs (map contentdb->package-name inputs))
@@ -507,9 +504,9 @@ or #false if the latest release couldn't be determined."
(upstream-source
(package (package:package-name pkg))
(version (release-version release))
- (urls (list (download:git-reference
- (url (package-repository contentdb-package))
- (commit (release-commit release))))))))
+ (urls (download:git-reference
+ (url (package-repository contentdb-package))
+ (commit (release-commit release)))))))
(define %minetest-updater
(upstream-updater
diff --git a/guix/import/texlive.scm b/guix/import/texlive.scm
index bdef9f58b0..c741555928 100644
--- a/guix/import/texlive.scm
+++ b/guix/import/texlive.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2017, 2021 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2017, 2021, 2022 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;;
;;; This file is part of GNU Guix.
@@ -18,6 +18,7 @@
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (guix import texlive)
+ #:use-module (ice-9 ftw)
#:use-module (ice-9 match)
#:use-module (ice-9 rdelim)
#:use-module (srfi srfi-1)
@@ -38,7 +39,8 @@
#:use-module (guix upstream)
#:use-module (guix packages)
#:use-module (guix build-system texlive)
- #:export (texlive->guix-package
+ #:export (files-differ?
+ texlive->guix-package
texlive-recursive-import))
;;; Commentary:
@@ -196,12 +198,53 @@
(loop all (record key value current field-type) key))))
(loop all current #false))))))))))))
+(define* (files-differ? directory package-name
+ #:key
+ (package-database tlpdb)
+ (type #false)
+ (direction 'missing))
+ "Return a list of files in DIRECTORY that differ from the expected installed
+files for PACKAGE-NAME according to the PACKAGE-DATABASE. By default all
+files considered, but this can be restricted by setting TYPE to 'runfiles,
+'docfiles, or 'srcfiles. The names of files that are missing from DIRECTORY
+are returned; by setting DIRECTION to anything other than 'missing, the names
+of those files are returned that are unexpectedly installed."
+ (define (strip-directory-prefix file-name)
+ (string-drop file-name (1+ (string-length directory))))
+ (let* ((data (or (assoc-ref (package-database) package-name)
+ (error (format #false
+ "~a is not a valid package name in the TeX Live package database."
+ package-name))))
+ (files (if type
+ (or (assoc-ref data type) (list))
+ (append (or (assoc-ref data 'runfiles) (list))
+ (or (assoc-ref data 'docfiles) (list))
+ (or (assoc-ref data 'srcfiles) (list)))))
+ (existing (file-system-fold
+ (const #true) ;enter?
+ (lambda (path stat result) (cons path result)) ;leaf
+ (lambda (path stat result) result) ;down
+ (lambda (path stat result) result) ;up
+ (lambda (path stat result) result) ;skip
+ (lambda (path stat errno result) result) ;error
+ (list)
+ directory)))
+ (if (eq? direction 'missing)
+ (lset-difference string=?
+ files (map strip-directory-prefix existing))
+ ;; List files that are installed but should not be.
+ (lset-difference string=?
+ (map strip-directory-prefix existing) files))))
+
(define (files->directories files)
+ (define name->parts (cut string-split <> #\/))
(map (cut string-join <> "/" 'suffix)
(delete-duplicates (map (lambda (file)
- (drop-right (string-split file #\/) 1))
- files)
- equal?)))
+ (drop-right (name->parts file) 1))
+ (sort files string<))
+ ;; Remove sub-directories, i.e. more specific
+ ;; entries with the same prefix.
+ (lambda (x y) (every equal? x y)))))
(define (tlpdb->package name package-database)
(and-let* ((data (assoc-ref package-database name))
@@ -236,10 +279,10 @@
,@(or (and=> (assoc-ref data 'depend)
(lambda (inputs)
`((propagated-inputs
- ,(map (lambda (tex-name)
- (let ((name (guix-name tex-name)))
- (list name (list 'unquote (string->symbol name)))))
- inputs)))))
+ (list ,@(map (lambda (tex-name)
+ (let ((name (guix-name tex-name)))
+ (string->symbol name)))
+ inputs))))))
'())
,@(or (and=> (assoc-ref data 'catalogue-ctan)
(lambda (url)
diff --git a/guix/inferior.scm b/guix/inferior.scm
index febac29766..572114f626 100644
--- a/guix/inferior.scm
+++ b/guix/inferior.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2018-2022 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -815,8 +815,8 @@ determines whether CHANNELS are authenticated."
(add-indirect-root* cached)
(return cached))
(mbegin %store-monad
- (add-temp-root* profile)
- (return profile))))))))
+ (add-temp-root* (derivation->output-path profile))
+ (return (derivation->output-path profile)))))))))
(define* (inferior-for-channels channels
#:key
diff --git a/guix/lint.scm b/guix/lint.scm
index 74b9a304d9..8615bb916c 100644
--- a/guix/lint.scm
+++ b/guix/lint.scm
@@ -571,7 +571,7 @@ or \"bash-minimal\" is not in its inputs. 'wrap-script' is not supported."
input-names)))
(define (check-procedure-body body)
(match body
- ;; Explicitely setting an interpreter is acceptable,
+ ;; Explicitely setting an interpreter is acceptable.
(('wrap-program _ '#:sh . _) '())
(('wrap-program _ . _)
(list (report-wrap-program-error package 'wrap-program)))
diff --git a/guix/packages.scm b/guix/packages.scm
index b00fa2f702..9d5b23eb8a 100644
--- a/guix/packages.scm
+++ b/guix/packages.scm
@@ -56,7 +56,6 @@
#:re-export (%current-system
%current-target-system
search-path-specification) ;for convenience
- #:re-export-and-replace (delete) ;used as syntactic keyword
#:replace ((define-public* . define-public))
#:export (content-hash
content-hash?
@@ -181,6 +180,11 @@
package->cross-derivation
origin->derivation))
+;; The 'source-module-closure' procedure ca. 1.2.0 did not recognize
+;; #:re-export-and-replace: <https://issues.guix.gnu.org/52694>.
+;; Work around it.
+(module-re-export! (current-module) '(delete) #:replace? #t)
+
;;; Commentary:
;;;
;;; This module provides a high-level mechanism to define packages in a
@@ -391,7 +395,7 @@ from forcing GEXP-PROMISE."
;; This is the list of system types that are supported. By default, we
;; expect all packages to build successfully here.
'("x86_64-linux" "i686-linux" "armhf-linux" "aarch64-linux" "mips64el-linux" "i586-gnu"
- "powerpc64le-linux" "powerpc-linux"))
+ "powerpc64le-linux" "powerpc-linux" "riscv64-linux"))
(define %hurd-systems
;; The GNU/Hurd systems for which support is being developed.
@@ -402,7 +406,7 @@ from forcing GEXP-PROMISE."
;;
;; XXX: MIPS is unavailable in CI:
;; <https://lists.gnu.org/archive/html/guix-devel/2017-03/msg00790.html>.
- (fold delete %supported-systems '("mips64el-linux" "powerpc-linux")))
+ (fold delete %supported-systems '("mips64el-linux" "powerpc-linux" "riscv64-linux")))
(define-inlinable (sanitize-inputs inputs)
"Sanitize INPUTS by turning it into a list of name/package tuples if it's
diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm
index 510cee727f..ec071402f4 100644
--- a/guix/scripts/environment.scm
+++ b/guix/scripts/environment.scm
@@ -1,6 +1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2014, 2015, 2018 David Thompson <davet@gnu.org>
-;;; Copyright © 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2015-2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2018 Mike Gerwitz <mtg@gnu.org>
;;;
;;; This file is part of GNU Guix.
@@ -975,7 +975,10 @@ command-line option processing with 'parse-command-line'."
(mwhen (assoc-ref opts 'check?)
(return
- (validate-child-shell-environment profile manifest)))
+ (if container?
+ (warning (G_ "'--check' is unnecessary \
+when using '--container'; doing nothing~%"))
+ (validate-child-shell-environment profile manifest))))
(cond
((assoc-ref opts 'search-paths)
diff --git a/guix/scripts/hash.scm b/guix/scripts/hash.scm
index d73e3d13dd..4e792c6a03 100644
--- a/guix/scripts/hash.scm
+++ b/guix/scripts/hash.scm
@@ -1,9 +1,10 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2016, 2017, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012-2014, 2016-2017, 2020-2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
;;; Copyright © 2016 Jan Nieuwenhuizen <janneke@gnu.org>
;;; Copyright © 2018 Tim Gesthuizen <tim.gesthuizen@yahoo.de>
;;; Copyright © 2021 Simon Tournier <zimon.toutoune@gmail.com>
+;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -24,6 +25,7 @@
#:use-module (gcrypt hash)
#:use-module (guix serialization)
#:use-module (guix ui)
+ #:use-module (guix hash)
#:use-module (guix scripts)
#:use-module (guix base16)
#:use-module (guix base32)
@@ -46,20 +48,14 @@
(define* (nar-hash file #:optional
(algorithm (assoc-ref %default-options 'hash-algorithm))
select?)
- (let-values (((port get-hash)
- (open-hash-port algorithm)))
- (write-file file port #:select? select?)
- (force-output port)
- (get-hash)))
+ (file-hash* file #:algorithm algorithm #:select? select? #:recursive? #true))
(define* (default-hash file #:optional
(algorithm (assoc-ref %default-options 'hash-algorithm))
select?)
(match file
("-" (port-hash algorithm (current-input-port)))
- (_
- (call-with-input-file file
- (cute port-hash algorithm <>)))))
+ (_ (file-hash* file #:algorithm algorithm #:recursive? #false))))
(define* (git-hash file #:optional
(algorithm (assoc-ref %default-options 'hash-algorithm))
@@ -69,7 +65,7 @@
((directory) #t)
(else #f)))
(if directory?
- (git-hash-directory file algorithm)
+ (git-hash-directory file algorithm #:select? select?)
(git-hash-file file algorithm)))
@@ -138,8 +134,9 @@ and 'base16' ('hex' and 'hexadecimal' can be used as well).\n"))
(alist-delete 'format result))))
(option '(#\r "recursive") #f #f
(lambda (opt name arg result)
- (warning (G_ "'--recursive' is deprecated, \
-use '--serializer' instead~%"))
+ (unless (eqv? name #\r)
+ (warning (G_ "'--recursive' is deprecated, \
+use '--serializer=nar' instead~%")))
(alist-cons 'serializer nar-hash
(alist-delete 'serializer result))))
(option '(#\S "serializer") #t #f
@@ -181,16 +178,6 @@ use '--serializer' instead~%"))
(parse-command-line args %options (list %default-options)
#:build-options? #f))
- (define (vcs-file? file stat)
- (case (stat:type stat)
- ((directory)
- (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
- ((regular)
- ;; Git sub-modules have a '.git' file that is a regular text file.
- (string=? (basename file) ".git"))
- (else
- #f)))
-
(let* ((opts (parse-options))
(args (filter-map (match-lambda
(('argument . value)
diff --git a/guix/scripts/home.scm b/guix/scripts/home.scm
index afc7d8b39c..2312e4d313 100644
--- a/guix/scripts/home.scm
+++ b/guix/scripts/home.scm
@@ -105,7 +105,7 @@ Some ACTIONS support additional ARGS.\n"))
"Return the verbosity level based on OPTS, the alist of parsed options."
(or (assoc-ref opts 'verbosity)
(if (eq? (assoc-ref opts 'action) 'build)
- 2 1)))
+ 3 1)))
(define %options
;; Specification of the command-line options.
@@ -137,7 +137,7 @@ Some ACTIONS support additional ARGS.\n"))
(print-build-trace? . #t)
(print-extended-build-trace? . #t)
(multiplexed-build-output? . #t)
- (verbosity . 3)
+ (verbosity . #f) ;default
(debug . 0)))
@@ -286,7 +286,7 @@ deploy the home environment described by these files.\n")
((describe)
(match (generation-number %guix-home)
(0
- (error (G_ "no home environment generation, nothing to describe~%")))
+ (leave (G_ "no home environment generation, nothing to describe~%")))
(generation
(display-home-environment-generation generation))))
((list-generations)
diff --git a/guix/scripts/home/import.scm b/guix/scripts/home/import.scm
index fbf89069a7..15bd3140ed 100644
--- a/guix/scripts/home/import.scm
+++ b/guix/scripts/home/import.scm
@@ -2,6 +2,7 @@
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
;;; Copyright © 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2022 Arjan Adriaanse <arjan@adriaan.se>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -164,7 +165,8 @@ user's files to CONFIGURATION-DIRECTORY; the generated sexp refers to them."
,@(delete-duplicates (concatenate modules)))
(home-environment
- (packages (map specification->package ,packages))
+ (packages (map (compose list specification->package+output)
+ ,packages))
(services (list ,@services)))))))))
(define* (import-manifest
diff --git a/guix/scripts/import/go.scm b/guix/scripts/import/go.scm
index f5cfea8683..f1970d3543 100644
--- a/guix/scripts/import/go.scm
+++ b/guix/scripts/import/go.scm
@@ -87,37 +87,38 @@ that are not yet in Guix"))
(parse-command-line args %options (list %default-options)
#:build-options? #f))
- (let* ((opts (parse-options))
- (args (filter-map (match-lambda
- (('argument . value)
- value)
- (_ #f))
- (reverse opts)))
- ;; Append the full version to the package symbol name when using
- ;; pinned versions.
- (package->definition* (if (assoc-ref opts 'pin-versions?)
- (cut package->definition <> 'full)
- package->definition)))
- (match args
- ((spec) ;e.g., github.com/golang/protobuf@v1.3.1
- (receive (name version)
- (package-name->name+version spec)
- (let ((arguments (list name
- #:goproxy (assoc-ref opts 'goproxy)
- #:version version
- #:pin-versions?
- (assoc-ref opts 'pin-versions?))))
- (if (assoc-ref opts 'recursive)
- ;; Recursive import.
- (map package->definition*
- (apply go-module-recursive-import arguments))
- ;; Single import.
- (let ((sexp (apply go-module->guix-package* arguments)))
- (unless sexp
- (leave (G_ "failed to download meta-data for module '~a'.~%")
- name))
- (package->definition* sexp))))))
- (()
- (leave (G_ "too few arguments~%")))
- ((many ...)
- (leave (G_ "too many arguments~%"))))))
+ (with-error-handling
+ (let* ((opts (parse-options))
+ (args (filter-map (match-lambda
+ (('argument . value)
+ value)
+ (_ #f))
+ (reverse opts)))
+ ;; Append the full version to the package symbol name when using
+ ;; pinned versions.
+ (package->definition* (if (assoc-ref opts 'pin-versions?)
+ (cut package->definition <> 'full)
+ package->definition)))
+ (match args
+ ((spec) ;e.g., github.com/golang/protobuf@v1.3.1
+ (receive (name version)
+ (package-name->name+version spec)
+ (let ((arguments (list name
+ #:goproxy (assoc-ref opts 'goproxy)
+ #:version version
+ #:pin-versions?
+ (assoc-ref opts 'pin-versions?))))
+ (if (assoc-ref opts 'recursive)
+ ;; Recursive import.
+ (map package->definition*
+ (apply go-module-recursive-import arguments))
+ ;; Single import.
+ (let ((sexp (apply go-module->guix-package* arguments)))
+ (unless sexp
+ (leave (G_ "failed to download meta-data for module '~a'.~%")
+ name))
+ (package->definition* sexp))))))
+ (()
+ (leave (G_ "too few arguments~%")))
+ ((many ...)
+ (leave (G_ "too many arguments~%")))))))
diff --git a/guix/scripts/import/texlive.scm b/guix/scripts/import/texlive.scm
index 4aeaa79eef..c5dcc07ea1 100644
--- a/guix/scripts/import/texlive.scm
+++ b/guix/scripts/import/texlive.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2017, 2021 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2017, 2021, 2022 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
;;;
;;; This file is part of GNU Guix.
@@ -81,7 +81,7 @@ Import and convert the Texlive package for PACKAGE-NAME.\n"))
((name)
(let ((sexp (texlive->guix-package name)))
(unless sexp
- (leave (G_ "failed to download description for package '~a'~%")
+ (leave (G_ "failed to import package '~a'~%")
name))
sexp))
(()
diff --git a/guix/scripts/offload.scm b/guix/scripts/offload.scm
index 9ddf458c13..925325ef5f 100644
--- a/guix/scripts/offload.scm
+++ b/guix/scripts/offload.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2014-2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2014-2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2017 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2020 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
@@ -231,6 +231,9 @@ number of seconds after which the connection times out."
;; stateless instead.
#:knownhosts "/dev/null"
+ ;; Likewise for ~/.ssh/config.
+ #:config "/dev/null"
+
;; We need lightweight compression when
;; exchanging full archives.
#:compression
diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm
index 4b9c5f210d..9699c70c6d 100644
--- a/guix/scripts/package.scm
+++ b/guix/scripts/package.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012-2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
;;; Copyright © 2013, 2015 Mark H Weaver <mhw@netris.org>
;;; Copyright © 2014, 2016 Alex Kost <alezost@gmail.com>
@@ -139,6 +139,7 @@ denote ranges as interpreted by 'matching-generations'."
(define* (build-and-use-profile store profile manifest
#:key
+ dry-run?
(hooks %default-profile-hooks)
allow-collisions?
bootstrap?)
@@ -154,6 +155,7 @@ hooks\" run when building the profile."
(prof (derivation->output-path prof-drv)))
(cond
+ (dry-run? #t)
((and (file-exists? profile)
(and=> (readlink* profile) (cut string=? prof <>)))
(format (current-error-port) (G_ "nothing to be done~%")))
@@ -1069,6 +1071,7 @@ processed, #f otherwise."
trans
#:dry-run? dry-run?)
(build-and-use-profile store profile new
+ #:dry-run? dry-run?
#:allow-collisions? allow-collisions?
#:bootstrap? bootstrap?)))))
diff --git a/guix/scripts/refresh.scm b/guix/scripts/refresh.scm
index 8806f0f740..68bb9040d8 100644
--- a/guix/scripts/refresh.scm
+++ b/guix/scripts/refresh.scm
@@ -8,6 +8,7 @@
;;; Copyright © 2018 Efraim Flashner <efraim@flashner.co.il>
;;; Copyright © 2019 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2020 Simon Tournier <zimon.toutoune@gmail.com>
+;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -26,7 +27,6 @@
(define-module (guix scripts refresh)
#:use-module (guix ui)
- #:use-module (gcrypt hash)
#:use-module (guix scripts)
#:use-module ((guix scripts build) #:select (%standard-build-options))
#:use-module (guix store)
@@ -38,6 +38,7 @@
#:use-module (guix scripts graph)
#:use-module (guix monads)
#:use-module (guix gnupg)
+ #:use-module (guix hash)
#:use-module (gnu packages)
#:use-module ((gnu packages commencement) #:select (%final-inputs))
#:use-module (ice-9 match)
@@ -314,14 +315,14 @@ KEY-DOWNLOAD specifies a download policy for missing OpenPGP keys; allowed
values: 'interactive' (default), 'always', and 'never'. When WARN? is true,
warn about packages that have no matching updater."
(if (lookup-updater package updaters)
- (let-values (((version tarball source)
+ (let-values (((version output source)
(package-update store package updaters
#:key-download key-download))
((loc)
(or (package-field-location package 'version)
(package-location package))))
(when version
- (if (and=> tarball file-exists?)
+ (if (and=> output file-exists?)
(begin
(info loc
(G_ "~a: updating from version ~a to version ~a...~%")
@@ -363,8 +364,7 @@ warn about packages that have no matching updater."
(info loc (G_ "~a: consider removing this propagated input: ~a~%")
name change-name))))
(upstream-source-input-changes source))
- (let ((hash (call-with-input-file tarball
- port-sha256)))
+ (let ((hash (file-hash* output)))
(update-package-source package source hash)))
(warning (G_ "~a: version ~a could not be \
downloaded and authenticated; not updating~%")
diff --git a/guix/scripts/shell.scm b/guix/scripts/shell.scm
index 546639818f..a92932cbc9 100644
--- a/guix/scripts/shell.scm
+++ b/guix/scripts/shell.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2021-2022 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -21,7 +21,8 @@
#:use-module ((guix diagnostics) #:select (location))
#:use-module (guix scripts environment)
#:autoload (guix scripts build) (show-build-options-help)
- #:autoload (guix transformations) (show-transformation-options-help)
+ #:autoload (guix transformations) (transformation-option-key?
+ show-transformation-options-help)
#:use-module (guix scripts)
#:use-module (guix packages)
#:use-module (guix profiles)
@@ -40,6 +41,7 @@
#:use-module ((guix build utils) #:select (mkdir-p))
#:use-module (guix cache)
#:use-module ((ice-9 ftw) #:select (scandir))
+ #:autoload (gnu packages) (cache-is-authoritative?)
#:export (guix-shell))
(define (show-help)
@@ -201,51 +203,35 @@ a hash-prefixed comment, or a blank line."
(const #f)))
(define (options-with-caching opts)
- "If OPTS contains exactly one 'load' or one 'manifest' key, automatically
-add a 'profile' key (when a profile for that file is already in cache) or a
-'gc-root' key (to add the profile to cache)."
- (define (single-file-for-caching opts)
- (let loop ((opts opts)
- (file #f))
- (match opts
- (() file)
- ((('package . _) . _) #f)
- ((('load . ('package candidate)) . rest)
- (and (not file) (loop rest candidate)))
- ((('manifest . candidate) . rest)
- (and (not file) (loop rest candidate)))
- ((('expression . _) . _) #f)
- ((_ . rest) (loop rest file)))))
-
- ;; Check whether there's a single 'load' or 'manifest' option. When that is
- ;; the case, arrange to automatically cache the resulting profile.
- (match (single-file-for-caching opts)
- (#f opts)
- (file
- (let* ((root (profile-cached-gc-root file))
- (stat (and root (false-if-exception (lstat root)))))
- (if (and (not (assoc-ref opts 'rebuild-cache?))
- stat
- (<= (stat:mtime ((@ (guile) stat) file))
- (stat:mtime stat)))
- (let ((now (current-time)))
- ;; Update the atime on ROOT to reflect usage.
- (utime root
- now (stat:mtime stat) 0 (stat:mtimensec stat)
- AT_SYMLINK_NOFOLLOW)
- (alist-cons 'profile root
- (remove (match-lambda
- (('load . _) #t)
- (('manifest . _) #t)
- (_ #f))
- opts))) ;load right away
- (if (and root (not (assq-ref opts 'gc-root)))
- (begin
- (if stat
- (delete-file root)
- (mkdir-p (dirname root)))
- (alist-cons 'gc-root root opts))
- opts))))))
+ "If OPTS contains only options that allow us to compute a cache key,
+automatically add a 'profile' key (when a profile for that file is already in
+cache) or a 'gc-root' key (to add the profile to cache)."
+ ;; Attempt to compute a file name for use as the cached profile GC root.
+ (let* ((root timestamp (profile-cached-gc-root opts))
+ (stat (and root (false-if-exception (lstat root)))))
+ (if (and (not (assoc-ref opts 'rebuild-cache?))
+ stat
+ (<= timestamp (stat:mtime stat)))
+ (let ((now (current-time)))
+ ;; Update the atime on ROOT to reflect usage.
+ (utime root
+ now (stat:mtime stat) 0 (stat:mtimensec stat)
+ AT_SYMLINK_NOFOLLOW)
+ (alist-cons 'profile root
+ (remove (match-lambda
+ (('load . _) #t)
+ (('manifest . _) #t)
+ (('package . _) #t)
+ (('ad-hoc-package . _) #t)
+ (_ #f))
+ opts))) ;load right away
+ (if (and root (not (assq-ref opts 'gc-root)))
+ (begin
+ (if stat
+ (delete-file root)
+ (mkdir-p (dirname root)))
+ (alist-cons 'gc-root root opts))
+ opts))))
(define (auto-detect-manifest opts)
"If OPTS do not specify packages or a manifest, load a \"guix.scm\" or
@@ -308,28 +294,87 @@ echo ~a >> ~a
(make-parameter (string-append (cache-directory #:ensure? #f)
"/profiles")))
-(define (profile-cache-key file)
+(define (profile-cache-primary-key)
+ "Return the \"primary key\" used when computing keys for the profile cache.
+Return #f if no such key can be obtained and caching cannot be
+performed--e.g., because the package cache is not authoritative."
+ (and (cache-is-authoritative?)
+ (match (current-channels)
+ (()
+ #f)
+ (((= channel-commit commits) ...)
+ (string-join commits)))))
+
+(define (profile-file-cache-key file system)
"Return the cache key for the profile corresponding to FILE, a 'guix.scm' or
'manifest.scm' file, or #f if we lack channel information."
- (match (current-channels)
- (() #f)
- (((= channel-commit commits) ...)
+ (match (profile-cache-primary-key)
+ (#f #f)
+ (primary-key
(let ((stat (stat file)))
(bytevector->base32-string
;; Since FILE is not canonicalized, only include the device/inode
;; numbers. XXX: In some rare cases involving Btrfs and NFS, this can
;; be insufficient: <https://lwn.net/Articles/866582/>.
(sha256 (string->utf8
- (string-append (string-join commits) ":"
+ (string-append primary-key ":" system ":"
(number->string (stat:dev stat)) ":"
(number->string (stat:ino stat))))))))))
-(define (profile-cached-gc-root file)
- "Return the cached GC root for FILE, a 'guix.scm' or 'manifest.scm' file, or
-#f if we lack information to cache it."
- (match (profile-cache-key file)
- (#f #f)
- (key (string-append (%profile-cache-directory) "/" key))))
+(define (profile-spec-cache-key specs system)
+ "Return the cache key corresponding to SPECS built for SYSTEM, where SPECS
+is a list of package specs. Return #f if caching is not possible."
+ (match (profile-cache-primary-key)
+ (#f #f)
+ (primary-key
+ (bytevector->base32-string
+ (sha256 (string->utf8
+ (string-append primary-key ":" system ":"
+ (object->string specs))))))))
+
+(define (profile-cached-gc-root opts)
+ "Return two values: the file name of a GC root for use as a profile cache
+for the options in OPTS, and a timestamp which, if greater than the GC root's
+mtime, indicates that the GC root is stale. If OPTS do not permit caching,
+return #f and #f."
+ (define (key->file key)
+ (string-append (%profile-cache-directory) "/" key))
+
+ (let loop ((opts opts)
+ (system (%current-system))
+ (file #f)
+ (specs '()))
+ (match opts
+ (()
+ (if file
+ (values (and=> (profile-file-cache-key file system) key->file)
+ (stat:mtime (stat file)))
+ (values (and=> (profile-spec-cache-key specs system) key->file)
+ 0)))
+ (((and spec ('package . _)) . rest)
+ (if (not file)
+ (loop rest system file (cons spec specs))
+ (values #f #f)))
+ ((('load . ('package candidate)) . rest)
+ (if (and (not file) (null? specs))
+ (loop rest system candidate specs)
+ (values #f #f)))
+ ((('manifest . candidate) . rest)
+ (if (and (not file) (null? specs))
+ (loop rest system candidate specs)
+ (values #f #f)))
+ ((('expression . _) . _)
+ ;; Arbitrary expressions might be non-deterministic or otherwise depend
+ ;; on external state so do not cache when they're used.
+ (values #f #f))
+ ((((? transformation-option-key?) . _) . _)
+ ;; Transformation options are potentially "non-deterministic", or at
+ ;; least depending on external state (with-source, with-commit, etc.),
+ ;; so do not cache anything when they're used.
+ (values #f #f))
+ ((('system . system) . rest)
+ (loop rest system file specs))
+ ((_ . rest) (loop rest system file specs)))))
;;;
diff --git a/guix/scripts/style.scm b/guix/scripts/style.scm
index 3b246e9c66..fb31c694f2 100644
--- a/guix/scripts/style.scm
+++ b/guix/scripts/style.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2021-2022 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -40,11 +40,16 @@
#:use-module (ice-9 control)
#:use-module (ice-9 match)
#:use-module (ice-9 rdelim)
+ #:use-module (ice-9 vlist)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-9)
#:use-module (srfi srfi-26)
#:use-module (srfi srfi-37)
- #:export (guix-style))
+ #:export (pretty-print-with-comments
+ read-with-comments
+ canonicalize-comment
+
+ guix-style))
;;;
@@ -109,93 +114,345 @@
;;; Comment-preserving pretty-printer.
;;;
+(define-syntax vhashq
+ (syntax-rules (quote)
+ ((_) vlist-null)
+ ((_ (key (quote (lst ...))) rest ...)
+ (vhash-consq key '(lst ...) (vhashq rest ...)))
+ ((_ (key value) rest ...)
+ (vhash-consq key '((() . value)) (vhashq rest ...)))))
+
+(define %special-forms
+ ;; Forms that are indented specially. The number is meant to be understood
+ ;; like Emacs' 'scheme-indent-function' symbol property. When given an
+ ;; alist instead of a number, the alist gives "context" in which the symbol
+ ;; is a special form; for instance, context (modify-phases) means that the
+ ;; symbol must appear within a (modify-phases ...) expression.
+ (vhashq
+ ('begin 1)
+ ('lambda 2)
+ ('lambda* 2)
+ ('match-lambda 1)
+ ('match-lambda* 2)
+ ('define 2)
+ ('define* 2)
+ ('define-public 2)
+ ('define*-public 2)
+ ('define-syntax 2)
+ ('define-syntax-rule 2)
+ ('define-module 2)
+ ('define-gexp-compiler 2)
+ ('let 2)
+ ('let* 2)
+ ('letrec 2)
+ ('letrec* 2)
+ ('match 2)
+ ('when 2)
+ ('unless 2)
+ ('package 1)
+ ('origin 1)
+ ('operating-system 1)
+ ('modify-inputs 2)
+ ('modify-phases 2)
+ ('add-after '(((modify-phases) . 3)))
+ ('add-before '(((modify-phases) . 3)))
+ ('replace '(((modify-phases) . 2))) ;different from 'modify-inputs'
+ ('substitute* 2)
+ ('substitute-keyword-arguments 2)
+ ('call-with-input-file 2)
+ ('call-with-output-file 2)
+ ('with-output-to-file 2)
+ ('with-input-from-file 2)))
+
+(define %newline-forms
+ ;; List heads that must be followed by a newline. The second argument is
+ ;; the context in which they must appear. This is similar to a special form
+ ;; of 1, except that indent is 1 instead of 2 columns.
+ (vhashq
+ ('arguments '(package))
+ ('sha256 '(origin source package))
+ ('base32 '(sha256 origin))
+ ('git-reference '(uri origin source))
+ ('search-paths '(package))
+ ('native-search-paths '(package))
+ ('search-path-specification '())))
+
+(define (prefix? candidate lst)
+ "Return true if CANDIDATE is a prefix of LST."
+ (let loop ((candidate candidate)
+ (lst lst))
+ (match candidate
+ (() #t)
+ ((head1 . rest1)
+ (match lst
+ (() #f)
+ ((head2 . rest2)
+ (and (equal? head1 head2)
+ (loop rest1 rest2))))))))
+
+(define (special-form-lead symbol context)
+ "If SYMBOL is a special form in the given CONTEXT, return its number of
+arguments; otherwise return #f. CONTEXT is a stack of symbols lexically
+surrounding SYMBOL."
+ (match (vhash-assq symbol %special-forms)
+ (#f #f)
+ ((_ . alist)
+ (any (match-lambda
+ ((prefix . level)
+ (and (prefix? prefix context) (- level 1))))
+ alist))))
+
+(define (newline-form? symbol context)
+ "Return true if parenthesized expressions starting with SYMBOL must be
+followed by a newline."
+ (match (vhash-assq symbol %newline-forms)
+ (#f #f)
+ ((_ . prefix)
+ (prefix? prefix context))))
+
+(define (escaped-string str)
+ "Return STR with backslashes and double quotes escaped. Everything else, in
+particular newlines, is left as is."
+ (list->string
+ `(#\"
+ ,@(string-fold-right (lambda (chr lst)
+ (match chr
+ (#\" (cons* #\\ #\" lst))
+ (#\\ (cons* #\\ #\\ lst))
+ (_ (cons chr lst))))
+ '()
+ str)
+ #\")))
+
+(define (string-width str)
+ "Return the \"width\" of STR--i.e., the width of the longest line of STR."
+ (apply max (map string-length (string-split str #\newline))))
+
+(define (canonicalize-comment c)
+ "Canonicalize comment C, ensuring it has the \"right\" number of leading
+semicolons."
+ (let ((line (string-trim-both
+ (string-trim (comment->string c) (char-set #\;)))))
+ (comment (string-append
+ (if (comment-margin? c)
+ ";"
+ (if (string-null? line)
+ ";;" ;no trailing space
+ ";; "))
+ line "\n")
+ (comment-margin? c))))
+
(define* (pretty-print-with-comments port obj
#:key
+ (format-comment identity)
(indent 0)
(max-width 78)
(long-list 5))
+ "Pretty-print OBJ to PORT, attempting to at most MAX-WIDTH character columns
+and assuming the current column is INDENT. Comments present in OBJ are
+included in the output.
+
+Lists longer than LONG-LIST are written as one element per line. Comments are
+passed through FORMAT-COMMENT before being emitted; a useful value for
+FORMAT-COMMENT is 'canonicalize-comment'."
(let loop ((indent indent)
(column indent)
(delimited? #t) ;true if comes after a delimiter
+ (context '()) ;list of "parent" symbols
(obj obj))
+ (define (print-sequence context indent column lst delimited?)
+ (define long?
+ (> (length lst) long-list))
+
+ (let print ((lst lst)
+ (first? #t)
+ (delimited? delimited?)
+ (column column))
+ (match lst
+ (()
+ column)
+ ((item . tail)
+ (define newline?
+ ;; Insert a newline if ITEM is itself a list, or if TAIL is long,
+ ;; but only if ITEM is not the first item. Also insert a newline
+ ;; before a keyword.
+ (and (or (pair? item) long?
+ (and (keyword? item)
+ (not (eq? item #:allow-other-keys))))
+ (not first?) (not delimited?)
+ (not (comment? item))))
+
+ (when newline?
+ (newline port)
+ (display (make-string indent #\space) port))
+ (let ((column (if newline? indent column)))
+ (print tail #f
+ (comment? item)
+ (loop indent column
+ (or newline? delimited?)
+ context
+ item)))))))
+
+ (define (sequence-would-protrude? indent lst)
+ ;; Return true if elements of LST written at INDENT would protrude
+ ;; beyond MAX-WIDTH. This is implemented as a cheap test with false
+ ;; negatives to avoid actually rendering all of LST.
+ (find (match-lambda
+ ((? string? str)
+ (>= (+ (string-width str) 2 indent) max-width))
+ ((? symbol? symbol)
+ (>= (+ (string-width (symbol->string symbol)) indent)
+ max-width))
+ ((? boolean?)
+ (>= (+ 2 indent) max-width))
+ (()
+ (>= (+ 2 indent) max-width))
+ (_ ;don't know
+ #f))
+ lst))
+
+ (define (special-form? head)
+ (special-form-lead head context))
+
(match obj
((? comment? comment)
(if (comment-margin? comment)
(begin
(display " " port)
- (display (comment->string comment) port))
+ (display (comment->string (format-comment comment))
+ port))
(begin
;; When already at the beginning of a line, for example because
;; COMMENT follows a margin comment, no need to emit a newline.
(unless (= column indent)
(newline port)
(display (make-string indent #\space) port))
- (display (comment->string comment) port)))
+ (display (comment->string (format-comment comment))
+ port)))
(display (make-string indent #\space) port)
indent)
(('quote lst)
(unless delimited? (display " " port))
(display "'" port)
- (loop indent (+ column (if delimited? 1 2)) #t lst))
+ (loop indent (+ column (if delimited? 1 2)) #t context lst))
(('quasiquote lst)
(unless delimited? (display " " port))
(display "`" port)
- (loop indent (+ column (if delimited? 1 2)) #t lst))
+ (loop indent (+ column (if delimited? 1 2)) #t context lst))
(('unquote lst)
(unless delimited? (display " " port))
(display "," port)
- (loop indent (+ column (if delimited? 1 2)) #t lst))
- (('modify-inputs inputs clauses ...)
- ;; Special-case 'modify-inputs' to have one clause per line and custom
- ;; indentation.
- (let ((head "(modify-inputs "))
+ (loop indent (+ column (if delimited? 1 2)) #t context lst))
+ (('unquote-splicing lst)
+ (unless delimited? (display " " port))
+ (display ",@" port)
+ (loop indent (+ column (if delimited? 2 3)) #t context lst))
+ (('gexp lst)
+ (unless delimited? (display " " port))
+ (display "#~" port)
+ (loop indent (+ column (if delimited? 2 3)) #t context lst))
+ (('ungexp obj)
+ (unless delimited? (display " " port))
+ (display "#$" port)
+ (loop indent (+ column (if delimited? 2 3)) #t context obj))
+ (('ungexp-native obj)
+ (unless delimited? (display " " port))
+ (display "#+" port)
+ (loop indent (+ column (if delimited? 2 3)) #t context obj))
+ (('ungexp-splicing lst)
+ (unless delimited? (display " " port))
+ (display "#$@" port)
+ (loop indent (+ column (if delimited? 3 4)) #t context lst))
+ (('ungexp-native-splicing lst)
+ (unless delimited? (display " " port))
+ (display "#+@" port)
+ (loop indent (+ column (if delimited? 3 4)) #t context lst))
+ (((? special-form? head) arguments ...)
+ ;; Special-case 'let', 'lambda', 'modify-inputs', etc. so the second
+ ;; and following arguments are less indented.
+ (let* ((lead (special-form-lead head context))
+ (context (cons head context))
+ (head (symbol->string head))
+ (total (length arguments)))
+ (unless delimited? (display " " port))
+ (display "(" port)
(display head port)
- (loop (+ indent 4)
- (+ column (string-length head))
- #t
- inputs)
- (let* ((indent (+ indent 2))
- (column (fold (lambda (clause column)
- (newline port)
- (display (make-string indent #\space)
- port)
- (loop indent indent #t clause))
- indent
- clauses)))
- (display ")" port)
- (+ column 1))))
+ (unless (zero? lead)
+ (display " " port))
+
+ ;; Print the first LEAD arguments.
+ (let* ((indent (+ column 2
+ (if delimited? 0 1)))
+ (column (+ column 1
+ (if (zero? lead) 0 1)
+ (if delimited? 0 1)
+ (string-length head)))
+ (initial-indent column))
+ (define new-column
+ (let inner ((n lead)
+ (arguments (take arguments (min lead total)))
+ (column column))
+ (if (zero? n)
+ (begin
+ (newline port)
+ (display (make-string indent #\space) port)
+ indent)
+ (match arguments
+ (() column)
+ ((head . tail)
+ (inner (- n 1) tail
+ (loop initial-indent column
+ (= n lead)
+ context
+ head)))))))
+
+ ;; Print the remaining arguments.
+ (let ((column (print-sequence
+ context indent new-column
+ (drop arguments (min lead total))
+ #t)))
+ (display ")" port)
+ (+ column 1)))))
((head tail ...)
- (unless delimited? (display " " port))
- (display "(" port)
- (let* ((new-column (loop indent (+ 1 column) #t head))
- (indent (+ indent (- new-column column)))
- (long? (> (length tail) long-list)))
- (define column
- (fold2 (lambda (item column first?)
- (define newline?
- ;; Insert a newline if ITEM is itself a list, or if TAIL
- ;; is long, but only if ITEM is not the first item.
- (and (or (pair? item) long?)
- (not first?) (not (comment? item))))
-
- (when newline?
- (newline port)
- (display (make-string indent #\space) port))
- (let ((column (if newline? indent column)))
- (values (loop indent
- column
- (= column indent)
- item)
- (comment? item))))
- (+ 1 new-column)
- #t ;first
- tail))
- (display ")" port)
- (+ column 1)))
+ (let* ((overflow? (>= column max-width))
+ (column (if overflow?
+ (+ indent 1)
+ (+ column (if delimited? 1 2))))
+ (newline? (newline-form? head context))
+ (context (cons head context)))
+ (if overflow?
+ (begin
+ (newline port)
+ (display (make-string indent #\space) port))
+ (unless delimited? (display " " port)))
+ (display "(" port)
+
+ (let* ((new-column (loop column column #t context head))
+ (indent (if (or (>= new-column max-width)
+ (not (symbol? head))
+ (sequence-would-protrude?
+ (+ new-column 1) tail)
+ newline?)
+ column
+ (+ new-column 1))))
+ (when newline?
+ ;; Insert a newline right after HEAD.
+ (newline port)
+ (display (make-string indent #\space) port))
+
+ (let ((column
+ (print-sequence context indent
+ (if newline? indent new-column)
+ tail newline?)))
+ (display ")" port)
+ (+ column 1)))))
(_
- (let* ((str (object->string obj))
- (len (string-length str)))
- (if (> (+ column 1 len) max-width)
+ (let* ((str (if (string? obj)
+ (escaped-string obj)
+ (object->string obj)))
+ (len (string-width str)))
+ (if (and (> (+ column 1 len) max-width)
+ (not delimited?))
(begin
(newline port)
(display (make-string indent #\space) port)
@@ -204,13 +461,14 @@
(begin
(unless delimited? (display " " port))
(display str port)
- (+ column (if delimited? 1 2) len))))))))
+ (+ column (if delimited? 0 1) len))))))))
-(define (object->string* obj indent)
+(define (object->string* obj indent . args)
(call-with-output-string
(lambda (port)
- (pretty-print-with-comments port obj
- #:indent indent))))
+ (apply pretty-print-with-comments port obj
+ #:indent indent
+ args))))
;;;
@@ -449,6 +707,31 @@ PACKAGE."
(list package-inputs package-native-inputs
package-propagated-inputs)))
+
+;;;
+;;; Formatting package definitions.
+;;;
+
+(define* (format-package-definition package
+ #:key policy
+ (edit-expression edit-expression))
+ "Reformat the definition of PACKAGE."
+ (unless (package-definition-location package)
+ (leave (package-location package)
+ (G_ "no definition location for package ~a~%")
+ (package-full-name package)))
+
+ (edit-expression
+ (location->source-properties
+ (absolute-location (package-definition-location package)))
+ (lambda (str)
+ (let ((exp (call-with-input-string str
+ read-with-comments)))
+ (object->string* exp
+ (location-column
+ (package-definition-location package))
+ #:format-comment canonicalize-comment)))))
+
(define (package-location<? p1 p2)
"Return true if P1's location is \"before\" P2's."
(let ((loc1 (package-location p1))
@@ -475,6 +758,15 @@ PACKAGE."
(option '(#\e "expression") #t #f
(lambda (opt name arg result)
(alist-cons 'expression arg result)))
+ (option '(#\S "styling") #t #f
+ (lambda (opt name arg result)
+ (alist-cons 'styling-procedure
+ (match arg
+ ("inputs" simplify-package-inputs)
+ ("format" format-package-definition)
+ (_ (leave (G_ "~a: unknown styling~%")
+ arg)))
+ result)))
(option '("input-simplification") #t #f
(lambda (opt name arg result)
(let ((symbol (string->symbol arg)))
@@ -496,6 +788,9 @@ PACKAGE."
(display (G_ "Usage: guix style [OPTION]... [PACKAGE]...
Update package definitions to the latest style.\n"))
(display (G_ "
+ -S, --styling=RULE apply RULE, a styling rule"))
+ (newline)
+ (display (G_ "
-n, --dry-run display files that would be edited but do nothing"))
(display (G_ "
-L, --load-path=DIR prepend DIR to the package module search path"))
@@ -515,7 +810,8 @@ Update package definitions to the latest style.\n"))
(define %default-options
;; Alist of default option values.
- '((input-simplification-policy . silent)))
+ `((input-simplification-policy . silent)
+ (styling-procedure . ,format-package-definition)))
;;;
@@ -542,11 +838,12 @@ Update package definitions to the latest style.\n"))
(edit (if (assoc-ref opts 'dry-run?)
edit-expression/dry-run
edit-expression))
+ (style (assoc-ref opts 'styling-procedure))
(policy (assoc-ref opts 'input-simplification-policy)))
(with-error-handling
(for-each (lambda (package)
- (simplify-package-inputs package #:policy policy
- #:edit-expression edit))
+ (style package #:policy policy
+ #:edit-expression edit))
;; Sort package by source code location so that we start editing
;; files from the bottom and going upward. That way, the
;; 'location' field of <package> records is not invalidated as
diff --git a/guix/scripts/substitute.scm b/guix/scripts/substitute.scm
index c044e1d47a..908a8334a8 100755
--- a/guix/scripts/substitute.scm
+++ b/guix/scripts/substitute.scm
@@ -237,7 +237,7 @@ was found."
;;;
(define (show-help)
- (display (G_ "Usage: guix substitute [OPTION]...
+ (display (G_ "Usage: guix substitute OPTION [ARGUMENT]...
Internal tool to substitute a pre-built binary to a local build.\n"))
(display (G_ "
--query report on the availability of substitutes for the
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
index 1db788a534..414e931c8a 100644
--- a/guix/scripts/system.scm
+++ b/guix/scripts/system.scm
@@ -57,6 +57,7 @@
#:use-module (guix build utils)
#:use-module (guix progress)
#:use-module ((guix build syscalls) #:select (terminal-columns))
+ #:use-module (gnu build image)
#:use-module (gnu build install)
#:autoload (gnu build file-systems)
(find-partition-by-label find-partition-by-uuid)
@@ -689,6 +690,7 @@ checking this by themselves in their 'check' procedure."
(define* (system-derivation-for-action image action
#:key
full-boot?
+ volatile?
(graphic? #t)
container-shared-network?
mappings)
@@ -707,22 +709,18 @@ checking this by themselves in their 'check' procedure."
((vm)
(system-qemu-image/shared-store-script os
#:full-boot? full-boot?
+ #:volatile? volatile?
#:graphic? graphic?
- #:disk-image-size
- (if full-boot?
- image-size
- (* 70 (expt 2 20)))
+ #:disk-image-size image-size
#:mappings mappings))
- ((image disk-image vm-image)
+ ((image disk-image vm-image docker-image)
(when (eq? action 'disk-image)
(warning (G_ "'disk-image' is deprecated: use 'image' instead~%")))
(when (eq? action 'vm-image)
(warning (G_ "'vm-image' is deprecated: use 'image' instead~%")))
- (lower-object (system-image image)))
- ((docker-image)
- (system-docker-image os
- #:memory-size 1024
- #:shared-network? container-shared-network?)))))
+ (when (eq? action 'docker-image)
+ (warning (G_ "'docker-image' is deprecated: use 'image' instead~%")))
+ (lower-object (system-image image))))))
(define (maybe-suggest-running-guix-pull)
"Suggest running 'guix pull' if this has never been done before."
@@ -774,6 +772,7 @@ and TARGET arguments."
dry-run? derivations-only?
use-substitutes? target
full-boot?
+ volatile-vm-root?
(graphic? #t)
container-shared-network?
(mappings '())
@@ -828,6 +827,8 @@ static checks."
(mlet* %store-monad
((sys (system-derivation-for-action image action
#:full-boot? full-boot?
+ #:volatile?
+ volatile-vm-root?
#:graphic? graphic?
#:container-shared-network? container-shared-network?
#:mappings mappings))
@@ -999,6 +1000,8 @@ Some ACTIONS support additional ARGS.\n"))
(display (G_ "
--volatile for 'image', make the root file system volatile"))
(display (G_ "
+ --persistent for 'vm', make the root file system persistent"))
+ (display (G_ "
--label=LABEL for 'image', label disk image with LABEL"))
(display (G_ "
--save-provenance save provenance information"))
@@ -1080,7 +1083,10 @@ Some ACTIONS support additional ARGS.\n"))
(alist-cons 'install-bootloader? #f result)))
(option '("volatile") #f #f
(lambda (opt name arg result)
- (alist-cons 'volatile-root? #t result)))
+ (alist-cons 'volatile-image-root? #t result)))
+ (option '("persistent") #f #f
+ (lambda (opt name arg result)
+ (alist-cons 'volatile-vm-root? #f result)))
(option '("label") #t #f
(lambda (opt name arg result)
(alist-cons 'label arg result)))
@@ -1149,7 +1155,8 @@ Some ACTIONS support additional ARGS.\n"))
(image-size . guess)
(install-bootloader? . #t)
(label . #f)
- (volatile-root? . #f)
+ (volatile-image-root? . #f)
+ (volatile-vm-root? . #t)
(graph-backend . "graphviz")))
(define (verbosity-level opts)
@@ -1214,11 +1221,15 @@ resulting from command-line parsing."
(label (assoc-ref opts 'label))
(image-type (lookup-image-type-by-name
(assoc-ref opts 'image-type)))
- (image (let* ((image-type (if (eq? action 'vm-image)
- qcow2-image-type
- image-type))
+ (image (let* ((image-type (case action
+ ((vm-image) qcow2-image-type)
+ ((docker-image) docker-image-type)
+ (else image-type)))
(image-size (assoc-ref opts 'image-size))
- (volatile? (assoc-ref opts 'volatile-root?))
+ (volatile?
+ (assoc-ref opts 'volatile-image-root?))
+ (shared-network?
+ (assoc-ref opts 'container-shared-network?))
(base-image (if (operating-system? obj)
(os->image obj
#:type image-type)
@@ -1228,7 +1239,8 @@ resulting from command-line parsing."
(image-with-label base-image label)
base-image))
(size image-size)
- (volatile-root? volatile?))))
+ (volatile-root? volatile?)
+ (shared-network? shared-network?))))
(os (image-operating-system image))
(target-file (match args
((first second) second)
@@ -1275,6 +1287,8 @@ resulting from command-line parsing."
#:validate-reconfigure
(assoc-ref opts 'validate-reconfigure)
#:full-boot? (assoc-ref opts 'full-boot?)
+ #:volatile-vm-root?
+ (assoc-ref opts 'volatile-vm-root?)
#:graphic? (not (assoc-ref opts 'no-graphic?))
#:container-shared-network?
(assoc-ref opts 'container-shared-network?)
@@ -1316,7 +1330,7 @@ argument list and OPTS is the option alist."
((describe)
(match (generation-number %system-profile)
(0
- (error (G_ "no system generation, nothing to describe~%")))
+ (leave (G_ "no system generation, nothing to describe~%")))
(generation
(display-system-generation generation))))
((search)
diff --git a/guix/self.scm b/guix/self.scm
index bd9a71de45..943bb0b498 100644
--- a/guix/self.scm
+++ b/guix/self.scm
@@ -64,6 +64,7 @@
("guile-gcrypt" (ref '(gnu packages gnupg) 'guile-gcrypt))
("gnutls" (ref '(gnu packages tls) 'gnutls))
("disarchive" (ref '(gnu packages backup) 'disarchive))
+ ("guile-lzma" (ref '(gnu packages guile) 'guile-lzma))
("gzip" (ref '(gnu packages compression) 'gzip))
("bzip2" (ref '(gnu packages compression) 'bzip2))
("xz" (ref '(gnu packages compression) 'xz))
@@ -789,6 +790,9 @@ itself."
(define disarchive
(specification->package "disarchive"))
+ (define guile-lzma
+ (specification->package "guile-lzma"))
+
(define dependencies
(append-map transitive-package-dependencies
(list guile-gcrypt gnutls guile-git guile-avahi
@@ -1009,7 +1013,9 @@ itself."
(command (guix-command modules
#:source source
#:dependencies
- (cons disarchive dependencies)
+ (cons* disarchive
+ guile-lzma
+ dependencies)
#:guile guile-for-build
#:guile-version guile-version)))
(whole-package name modules dependencies
diff --git a/guix/tests/git.scm b/guix/tests/git.scm
index 69960284d9..94f1021c79 100644
--- a/guix/tests/git.scm
+++ b/guix/tests/git.scm
@@ -23,9 +23,10 @@
#:use-module (guix utils)
#:use-module (guix build utils)
#:use-module (ice-9 match)
- #:use-module (ice-9 control)
+ #:use-module ((ice-9 control) #:select (let/ec))
#:export (git-command
with-temporary-git-repository
+ with-git-repository
find-commit))
(define git-command
@@ -59,8 +60,9 @@ Return DIRECTORY on success."
(apply invoke (git-command) "-C" directory
command args)))))
- (mkdir-p directory)
- (git "init")
+ (unless (directory-exists? (string-append directory "/.git"))
+ (mkdir-p directory)
+ (git "init"))
(let loop ((directives directives))
(match directives
@@ -78,6 +80,9 @@ Return DIRECTORY on success."
port)))
(git "add" file)
(loop rest)))
+ ((('add file-name-and-content) rest ...)
+ (loop (cons `(add ,file-name-and-content ,file-name-and-content)
+ rest)))
((('remove file) rest ...)
(git "rm" "-f" file)
(loop rest))
@@ -99,12 +104,18 @@ Return DIRECTORY on success."
((('checkout branch) rest ...)
(git "checkout" branch)
(loop rest))
+ ((('checkout branch 'orphan) rest ...)
+ (git "checkout" "--orphan" branch)
+ (loop rest))
((('merge branch message) rest ...)
(git "merge" branch "-m" message)
(loop rest))
((('merge branch message ('signer fingerprint)) rest ...)
(git "merge" branch "-m" message
(string-append "--gpg-sign=" fingerprint))
+ (loop rest))
+ ((('reset to) rest ...)
+ (git "reset" "--hard" to)
(loop rest)))))
(define (call-with-temporary-git-repository directives proc)
@@ -121,6 +132,14 @@ per DIRECTIVES."
(lambda (directory)
exp ...)))
+(define-syntax-rule (with-git-repository directory
+ directives exp ...)
+ "Evaluate EXP in a context where DIRECTORY is (further) populated as
+per DIRECTIVES."
+ (begin
+ (populate-git-repository directory directives)
+ exp ...))
+
(define (find-commit repository message)
"Return the commit in REPOSITORY whose message includes MESSAGE, a string."
(let/ec return
diff --git a/guix/tests/gnupg.scm b/guix/tests/gnupg.scm
index eb8ff63a43..09f02a2b67 100644
--- a/guix/tests/gnupg.scm
+++ b/guix/tests/gnupg.scm
@@ -28,11 +28,14 @@
%ed25519-public-key-file
%ed25519-secret-key-file
- %ed25519bis-public-key-file
- %ed25519bis-secret-key-file
+ %ed25519-2-public-key-file
+ %ed25519-2-secret-key-file
+ %ed25519-3-public-key-file
+ %ed25519-3-secret-key-file
read-openpgp-packet
key-fingerprint
+ key-fingerprint-vector
key-id))
(define gpg-command
@@ -63,20 +66,27 @@ process is terminated afterwards."
(call-with-fresh-gnupg-setup imported (lambda () exp ...)))
(define %ed25519-public-key-file
- (search-path %load-path "tests/ed25519.key"))
+ (search-path %load-path "tests/keys/ed25519.pub"))
(define %ed25519-secret-key-file
- (search-path %load-path "tests/ed25519.sec"))
-(define %ed25519bis-public-key-file
- (search-path %load-path "tests/ed25519bis.key"))
-(define %ed25519bis-secret-key-file
- (search-path %load-path "tests/ed25519bis.sec"))
+ (search-path %load-path "tests/keys/ed25519.sec"))
+(define %ed25519-2-public-key-file
+ (search-path %load-path "tests/keys/ed25519-2.pub"))
+(define %ed25519-2-secret-key-file
+ (search-path %load-path "tests/keys/ed25519-2.sec"))
+(define %ed25519-3-public-key-file
+ (search-path %load-path "tests/keys/ed25519-3.pub"))
+(define %ed25519-3-secret-key-file
+ (search-path %load-path "tests/keys/ed25519-3.sec"))
(define (read-openpgp-packet file)
(get-openpgp-packet
(open-bytevector-input-port
(call-with-input-file file read-radix-64))))
+(define key-fingerprint-vector
+ (compose openpgp-public-key-fingerprint
+ read-openpgp-packet))
+
(define key-fingerprint
(compose openpgp-format-fingerprint
- openpgp-public-key-fingerprint
- read-openpgp-packet))
+ key-fingerprint-vector))
diff --git a/guix/transformations.scm b/guix/transformations.scm
index 5ae1977cb2..0976f0d824 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, 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2016-2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2021 Marius Bakke <marius@gnu.org>
;;;
;;; This file is part of GNU Guix.
@@ -18,9 +18,11 @@
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (guix transformations)
+ #:use-module ((guix config) #:select (%system))
#:use-module (guix i18n)
#:use-module (guix store)
#:use-module (guix packages)
+ #:use-module (guix build-system)
#:use-module (guix profiles)
#:use-module (guix diagnostics)
#:autoload (guix download) (download-to-store)
@@ -29,6 +31,7 @@
#:autoload (guix upstream) (package-latest-release
upstream-source-version
upstream-source-signature-urls)
+ #:autoload (guix cpu) (current-cpu cpu->gcc-architecture)
#:use-module (guix utils)
#:use-module (guix memoization)
#:use-module (guix gexp)
@@ -49,7 +52,11 @@
#:export (options->transformation
manifest-entry-with-transformations
+ tunable-package?
+ tuned-package
+
show-transformation-options-help
+ transformation-option-key?
%transformation-options))
;;; Commentary:
@@ -419,6 +426,181 @@ the equal sign."
obj)
obj)))
+(define tuning-compiler
+ (mlambda (micro-architecture)
+ "Return a compiler wrapper that passes '-march=MICRO-ARCHITECTURE' to the
+actual compiler."
+ (define wrapper
+ #~(begin
+ (use-modules (ice-9 match))
+
+ (define* (search-next command
+ #:optional
+ (path (string-split (getenv "PATH")
+ #\:)))
+ ;; Search the next COMMAND on PATH, a list of
+ ;; directories representing the executable search path.
+ (define this
+ (stat (car (command-line))))
+
+ (let loop ((path path))
+ (match path
+ (()
+ (match command
+ ("cc" (search-next "gcc"))
+ (_ #f)))
+ ((directory rest ...)
+ (let* ((file (string-append
+ directory "/" command))
+ (st (stat file #f)))
+ (if (and st (not (equal? this st)))
+ file
+ (loop rest)))))))
+
+ (match (command-line)
+ ((command arguments ...)
+ (match (search-next (basename command))
+ (#f (exit 127))
+ (next
+ (apply execl next
+ (append (cons next arguments)
+ (list (string-append "-march="
+ #$micro-architecture))))))))))
+
+ (define program
+ (program-file (string-append "tuning-compiler-wrapper-" micro-architecture)
+ wrapper))
+
+ (computed-file (string-append "tuning-compiler-" micro-architecture)
+ (with-imported-modules '((guix build utils))
+ #~(begin
+ (use-modules (guix build utils))
+
+ (define bin (string-append #$output "/bin"))
+ (mkdir-p bin)
+
+ (for-each (lambda (program)
+ (symlink #$program
+ (string-append bin "/" program)))
+ '("cc" "gcc" "clang" "g++" "c++" "clang++")))))))
+
+(define (build-system-with-tuning-compiler bs micro-architecture)
+ "Return a variant of BS, a build system, that ensures that the compiler that
+BS uses (usually an implicit input) can generate code for MICRO-ARCHITECTURE,
+which names a specific CPU of the target architecture--e.g., when targeting
+86_64 MICRO-ARCHITECTURE might be \"skylake\". If it does, return a build
+system that builds code for MICRO-ARCHITECTURE; otherwise raise an error."
+ (define %not-hyphen
+ (char-set-complement (char-set #\-)))
+
+ (define lower
+ (build-system-lower bs))
+
+ (define (lower* . args)
+ ;; The list of CPU names supported by the '-march' option of C/C++
+ ;; compilers is specific to each compiler and version thereof. Rather
+ ;; than pass '-march=MICRO-ARCHITECTURE' as is to the compiler, possibly
+ ;; leading to an obscure build error, check whether the compiler is known
+ ;; to support MICRO-ARCHITECTURE. If not, bail out.
+ (let* ((lowered (apply lower args))
+ (architecture (match (string-tokenize (bag-system lowered)
+ %not-hyphen)
+ ((arch _ ...) arch)))
+ (compiler (any (match-lambda
+ ((label (? package? p) . _)
+ (and (assoc-ref (package-properties p)
+ 'compiler-cpu-architectures)
+ p))
+ (_ #f))
+ (bag-build-inputs lowered))))
+ (unless compiler
+ (raise (formatted-message
+ (G_ "failed to determine which compiler is used"))))
+
+ (let ((lst (assoc-ref (package-properties compiler)
+ 'compiler-cpu-architectures)))
+ (unless lst
+ (raise (formatted-message
+ (G_ "failed to determine whether ~a supports ~a")
+ (package-full-name compiler)
+ micro-architecture)))
+ (unless (member micro-architecture
+ (or (assoc-ref lst architecture) '()))
+ (raise (formatted-message
+ (G_ "compiler ~a does not support micro-architecture ~a")
+ (package-full-name compiler)
+ micro-architecture))))
+
+ (bag
+ (inherit lowered)
+ (build-inputs
+ ;; Arrange so that the compiler wrapper comes first in $PATH.
+ `(("tuning-compiler" ,(tuning-compiler micro-architecture))
+ ,@(bag-build-inputs lowered))))))
+
+ (build-system
+ (inherit bs)
+ (lower lower*)))
+
+(define (tuned-package p micro-architecture)
+ "Return package P tuned for MICRO-ARCHITECTURE."
+ (package
+ (inherit p)
+ (build-system
+ (build-system-with-tuning-compiler (package-build-system p)
+ micro-architecture))
+ (arguments
+ ;; The machine building this package may or may not be able to run code
+ ;; for MICRO-ARCHITECTURE. Because of that, skip tests; they are run for
+ ;; the "baseline" variant anyway.
+ (substitute-keyword-arguments (package-arguments p)
+ ((#:tests? _ #f) #f)))
+
+ (properties
+ `((cpu-tuning . ,micro-architecture)
+
+ ;; Remove the 'tunable?' property so that 'package-tuning' does not
+ ;; call 'tuned-package' again on this one.
+ ,@(alist-delete 'tunable? (package-properties p))))))
+
+(define (tunable-package? package)
+ "Return true if package PACKAGE is \"tunable\"--i.e., if tuning it for the
+host CPU is worthwhile."
+ (assq 'tunable? (package-properties package)))
+
+(define package-tuning
+ (mlambda (micro-architecture)
+ "Return a procedure that maps the given package to its counterpart tuned
+for MICRO-ARCHITECTURE, a string suitable for GCC's '-march'."
+ (define rewriting-property
+ (gensym " package-tuning"))
+
+ (package-mapping (lambda (p)
+ (cond ((assq rewriting-property (package-properties p))
+ p)
+ ((assq 'tunable? (package-properties p))
+ (info (G_ "tuning ~a for CPU ~a~%")
+ (package-full-name p) micro-architecture)
+ (package/inherit p
+ (replacement (tuned-package p micro-architecture))
+ (properties `((,rewriting-property . #t)
+ ,@(package-properties p)))))
+ (else
+ p)))
+ (lambda (p)
+ (assq rewriting-property (package-properties p)))
+ #:deep? #t)))
+
+(define (transform-package-tuning micro-architectures)
+ "Return a procedure that, when "
+ (match micro-architectures
+ ((micro-architecture _ ...)
+ (let ((rewrite (package-tuning micro-architecture)))
+ (lambda (obj)
+ (if (package? obj)
+ (rewrite obj)
+ obj))))))
+
(define (transform-package-with-debug-info specs)
"Return a procedure that, when passed a package, set its 'replacement' field
to the same package but with #:strip-binaries? #f in its 'arguments' field."
@@ -601,6 +783,7 @@ are replaced by their latest upstream version."
(with-commit . ,transform-package-source-commit)
(with-git-url . ,transform-package-source-git-url)
(with-c-toolchain . ,transform-package-toolchain)
+ (tune . ,transform-package-tuning)
(with-debug-info . ,transform-package-with-debug-info)
(without-tests . ,transform-package-tests)
(with-patch . ,transform-package-patches)
@@ -614,6 +797,12 @@ are replaced by their latest upstream version."
(and (eq? k key) proc)))
%transformations))
+(define (transformation-option-key? key)
+ "Return true if KEY is an option key (as returned while parsing options with
+%TRANSFORMATION-OPTIONS) corresponding to a package transformation option.
+For example, (transformation-option-key? 'with-input) => #t."
+ (->bool (transformation-procedure key)))
+
;;;
;;; Command-line handling.
@@ -640,6 +829,28 @@ are replaced by their latest upstream version."
(parser 'with-git-url))
(option '("with-c-toolchain") #t #f
(parser 'with-c-toolchain))
+ (option '("tune") #f #t
+ (lambda (opt name arg result . rest)
+ (define micro-architecture
+ (match arg
+ ((or #f "native")
+ (unless (string=? (or (assoc-ref result 'system)
+ (%current-system))
+ %system)
+ (leave (G_ "\
+building for ~a instead of ~a, so tuning cannot be guessed~%")
+ (assoc-ref result 'system) %system))
+
+ (cpu->gcc-architecture (current-cpu)))
+ ("generic" #f)
+ (_ arg)))
+
+ (apply values
+ (if micro-architecture
+ (alist-cons 'tune micro-architecture
+ result)
+ (alist-delete 'tune result))
+ rest)))
(option '("with-debug-info") #t #f
(parser 'with-debug-info))
(option '("without-tests") #t #f
diff --git a/guix/ui.scm b/guix/ui.scm
index bd999103ff..093de1b4ab 100644
--- a/guix/ui.scm
+++ b/guix/ui.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012-2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2013, 2018 Mark H Weaver <mhw@netris.org>
;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
;;; Copyright © 2014 Cyril Roelandt <tipecaml@gmail.com>
@@ -521,7 +521,7 @@ See the \"Application Setup\" section in the manual, for more info.\n"))
"Display version information for COMMAND and `(exit 0)'."
(simple-format #t "~a (~a) ~a~%"
command %guix-package-name %guix-version)
- (format #t "Copyright ~a 2021 ~a"
+ (format #t "Copyright ~a 2022 ~a"
;; TRANSLATORS: Translate "(C)" to the copyright symbol
;; (C-in-a-circle), if this symbol is available in the user's
;; locale. Otherwise, do not translate "(C)"; leave it as-is. */
@@ -940,7 +940,7 @@ warning."
(define (colorize-store-file-name file)
"Colorize FILE, a store file name, such that the hash part is less prominent
-that the rest."
+than the rest."
(let ((len (string-length file))
(prefix (+ (string-length (%store-prefix)) 32 2)))
(if (< len prefix)
@@ -1514,13 +1514,15 @@ HYPERLINKS? is true, emit hyperlink escape sequences when appropriate."
;; the initial "+ " prefix.
(if (> width 2) (- width 2) width))
+ (define (split-lines str indent)
+ (string->recutils
+ (fill-paragraph str width* indent)))
+
(define (dependencies->recutils packages)
(let ((list (string-join (delete-duplicates
(map package-full-name
(sort packages package<?))) " ")))
- (string->recutils
- (fill-paragraph list width*
- (string-length "dependencies: ")))))
+ (split-lines list (string-length "dependencies: "))))
(define (package<? p1 p2)
(string<? (package-full-name p1) (package-full-name p2)))
@@ -1530,7 +1532,8 @@ HYPERLINKS? is true, emit hyperlink escape sequences when appropriate."
(format port "version: ~a~%" (package-version p))
(format port "outputs: ~a~%" (string-join (package-outputs p)))
(format port "systems: ~a~%"
- (string-join (package-transitive-supported-systems p)))
+ (split-lines (string-join (package-transitive-supported-systems p))
+ (string-length "systems: ")))
(format port "dependencies: ~a~%"
(match (package-direct-inputs p)
(((labels inputs . _) ...)
diff --git a/guix/upstream.scm b/guix/upstream.scm
index 632e9ebc4f..6666803a92 100644
--- a/guix/upstream.scm
+++ b/guix/upstream.scm
@@ -1,7 +1,9 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2015 Alex Kost <alezost@gmail.com>
-;;; Copyright © 2019 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2019, 2022 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
+;;; Copyright © 2021, 2022 Maxime Devos <maximedevos@telenet.be>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -24,12 +26,15 @@
#:use-module (guix discovery)
#:use-module ((guix download)
#:select (download-to-store url-fetch))
+ #:use-module (guix git-download)
#:use-module (guix gnupg)
#:use-module (guix packages)
#:use-module (guix diagnostics)
#:use-module (guix ui)
#:use-module (guix base32)
#:use-module (guix gexp)
+ #:autoload (guix git) (latest-repository-commit git-reference->git-checkout)
+ #:use-module (guix hash)
#:use-module (guix store)
#:use-module ((guix derivations) #:select (built-derivations derivation->output-path))
#:autoload (gcrypt hash) (port-sha256)
@@ -93,7 +98,7 @@
upstream-source?
(package upstream-source-package) ;string
(version upstream-source-version) ;string
- (urls upstream-source-urls) ;list of strings
+ (urls upstream-source-urls) ;list of strings|git-reference
(signature-urls upstream-source-signature-urls ;#f | list of strings
(default #f))
(input-changes upstream-source-input-changes
@@ -117,16 +122,22 @@ S-expression PACKAGE-SEXP."
(match expr
((path *** ('inputs
('quasiquote ((label ('unquote sym)) ...)))) label)
+ ((path *** ('inputs
+ ('list sym ...))) (map symbol->string sym))
(_ '())))
(new-native
(match expr
((path *** ('native-inputs
('quasiquote ((label ('unquote sym)) ...)))) label)
+ ((path *** ('native-inputs
+ ('list sym ...))) (map symbol->string sym))
(_ '())))
(new-propagated
(match expr
((path *** ('propagated-inputs
('quasiquote ((label ('unquote sym)) ...)))) label)
+ ((path *** ('propagated-inputs
+ ('list sym ...))) (map symbol->string sym))
(_ '())))
(current-regular
(map input->name (package-inputs package)))
@@ -357,10 +368,9 @@ 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."
+(define (upstream-source-compiler/url-fetch source system)
+ "Lower SOURCE, an <upstream-source> pointing to a tarball, as a
+fixed-output derivation that would fetch it, and verify its authenticity."
(mlet* %store-monad ((url -> (first (upstream-source-urls source)))
(signature
-> (and=> (upstream-source-signature-urls source)
@@ -378,6 +388,30 @@ derivation that would fetch it."
(url-fetch url 'sha256 hash (store-path-package-name tarball)
#:system system))))
+(define (upstream-source-compiler/git-fetch source system)
+ "Lower SOURCE, an <upstream-source> using git, as a fixed-output
+derivation that would fetch it."
+ (mlet* %store-monad ((reference -> (upstream-source-urls source))
+ (checkout
+ (lower-object
+ (git-reference->git-checkout reference)
+ system)))
+ ;; Like in 'upstream-source-compiler/url-fetch', return a fixed-output
+ ;; derivation instead of CHECKOUT.
+ (git-fetch reference 'sha256
+ (file-hash* checkout #:recursive? #true #:select? (const #true))
+ (git-file-name (upstream-source-package source)
+ (upstream-source-version source))
+ #:system system)))
+
+(define-gexp-compiler (upstream-source-compiler (source <upstream-source>)
+ system target)
+ "Download SOURCE, lower it as a fixed-output derivation that would fetch it,
+and verify its authenticity if possible."
+ (if (git-reference? (upstream-source-urls source))
+ (upstream-source-compiler/git-fetch source system)
+ (upstream-source-compiler/url-fetch source 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."
@@ -430,9 +464,24 @@ SOURCE, an <upstream-source>."
#:key-download key-download)))
(values version tarball source))))))
+(define* (package-update/git-fetch store package source #:key key-download)
+ "Return the version, checkout, and SOURCE, to update PACKAGE to
+SOURCE, an <upstream-source>."
+ ;; TODO: it would be nice to authenticate commits, e.g. with
+ ;; "guix git authenticate" or a list of permitted signing keys.
+ (define ref (upstream-source-urls source)) ; a <git-reference>
+ (values (upstream-source-version source)
+ (latest-repository-commit
+ store
+ (git-reference-url ref)
+ #:ref `(tag-or-commit . ,(git-reference-commit ref))
+ #:recursive? (git-reference-recursive? ref))
+ source))
+
(define %method-updates
;; Mapping of origin methods to source update procedures.
- `((,url-fetch . ,package-update/url-fetch)))
+ `((,url-fetch . ,package-update/url-fetch)
+ (,git-fetch . ,package-update/git-fetch)))
(define* (package-update store package
#:optional (updaters (force %updaters))
@@ -492,9 +541,22 @@ new version string if an update was made, and #f otherwise."
(origin-hash (package-source package))))
(old-url (match (origin-uri (package-source package))
((? string? url) url)
+ ((? git-reference? ref)
+ (git-reference-url ref))
(_ #f)))
(new-url (match (upstream-source-urls source)
- ((first _ ...) first)))
+ ((first _ ...) first)
+ ((? git-reference? ref)
+ (git-reference-url ref))
+ (_ #f)))
+ (old-commit (match (origin-uri (package-source package))
+ ((? git-reference? ref)
+ (git-reference-commit ref))
+ (_ #f)))
+ (new-commit (match (upstream-source-urls source)
+ ((? git-reference? ref)
+ (git-reference-commit ref))
+ (_ #f)))
(file (and=> (location-file loc)
(cut search-path %load-path <>))))
(if file
@@ -508,6 +570,9 @@ new version string if an update was made, and #f otherwise."
'filename file))
(replacements `((,old-version . ,version)
(,old-hash . ,hash)
+ ,@(if (and old-commit new-commit)
+ `((,old-commit . ,new-commit))
+ '())
,@(if (and old-url new-url)
`((,(dirname old-url) .
,(dirname new-url)))
diff --git a/guix/utils.scm b/guix/utils.scm
index 9596ff8582..cba6464523 100644
--- a/guix/utils.scm
+++ b/guix/utils.scm
@@ -668,7 +668,7 @@ a character other than '@'."
"Is the architecture of TARGET a variant of Intel's 32-bit architecture
(IA32)?"
;; Intel also has a 16-bit architecture in the iN86 series, i286
- ;; (see, e.g. https://en.wikipedia.org/wiki/Intel/808286) so this
+ ;; (see, e.g., https://en.wikipedia.org/wiki/Intel_80286) so this
;; procedure is not named target-x86?.
(or (string-prefix? "i386-" target)
(string-prefix? "i486-" target)
@@ -712,7 +712,8 @@ architecture (x86_64)?"
(define* (target-64bit? #:optional (system (or (%current-target-system)
(%current-system))))
- (any (cut string-prefix? <> system) '("x86_64" "aarch64" "mips64" "powerpc64")))
+ (any (cut string-prefix? <> system) '("x86_64" "aarch64" "mips64"
+ "powerpc64" "riscv64")))
(define* (cc-for-target #:optional (target (%current-target-system)))
(if target