aboutsummaryrefslogtreecommitdiff
path: root/guix
diff options
context:
space:
mode:
authorLiliana Marie Prikler <liliana.prikler@gmail.com>2024-01-21 09:59:52 +0100
committerLiliana Marie Prikler <liliana.prikler@gmail.com>2024-01-21 09:59:55 +0100
commitff1ec930e5baa00b483f1ce43fa8bec18c797c03 (patch)
tree1c102408d5d79e12b70fe81f97602d3856ed334e /guix
parent60c97924e9519361494aaf0686e28eb831a42315 (diff)
parentc7f937cfdd9a08bad81705fe731e9fa5937cf562 (diff)
downloadguix-ff1ec930e5baa00b483f1ce43fa8bec18c797c03.tar
guix-ff1ec930e5baa00b483f1ce43fa8bec18c797c03.tar.gz
Merge branch 'master' into emacs-team
Diffstat (limited to 'guix')
-rw-r--r--guix/build-system/ant.scm2
-rw-r--r--guix/build-system/cargo.scm139
-rw-r--r--guix/build-system/clojure.scm4
-rw-r--r--guix/build-system/composer.scm166
-rw-r--r--guix/build-system/gnu.scm7
-rw-r--r--guix/build-system/guile.scm8
-rw-r--r--guix/build-system/meson.scm16
-rw-r--r--guix/build-system/mix.scm186
-rw-r--r--guix/build-system/perl.scm4
-rw-r--r--guix/build-system/r.scm2
-rw-r--r--guix/build-system/vim.scm170
-rw-r--r--guix/build-system/zig.scm119
-rw-r--r--guix/build/ant-build-system.scm31
-rw-r--r--guix/build/cargo-build-system.scm69
-rw-r--r--guix/build/composer-build-system.scm301
-rw-r--r--guix/build/git.scm19
-rw-r--r--guix/build/guile-build-system.scm13
-rw-r--r--guix/build/minetest-build-system.scm3
-rw-r--r--guix/build/mix-build-system.scm161
-rw-r--r--guix/build/syscalls.scm22
-rw-r--r--guix/build/vim-build-system.scm119
-rw-r--r--guix/build/zig-build-system.scm7
-rw-r--r--guix/deprecation.scm2
-rw-r--r--guix/docker.scm212
-rw-r--r--guix/download.scm28
-rw-r--r--guix/gexp.scm31
-rw-r--r--guix/git-download.scm97
-rw-r--r--guix/git.scm43
-rw-r--r--guix/grafts.scm6
-rw-r--r--guix/import/cabal.scm53
-rw-r--r--guix/import/composer.scm268
-rw-r--r--guix/import/cran.scm64
-rw-r--r--guix/import/crate.scm233
-rw-r--r--guix/import/go.scm37
-rw-r--r--guix/import/hackage.scm2
-rw-r--r--guix/import/stackage.scm2
-rw-r--r--guix/inferior.scm60
-rw-r--r--guix/least-authority.scm25
-rw-r--r--guix/lint.scm3
-rw-r--r--guix/monad-repl.scm74
-rw-r--r--guix/packages.scm14
-rw-r--r--guix/platform.scm3
-rw-r--r--guix/platforms/arm.scm2
-rw-r--r--guix/platforms/avr.scm28
-rw-r--r--guix/platforms/mips.scm1
-rw-r--r--guix/platforms/powerpc.scm3
-rw-r--r--guix/platforms/riscv.scm1
-rw-r--r--guix/platforms/x86.scm15
-rw-r--r--guix/profiles.scm37
-rw-r--r--guix/progress.scm3
-rw-r--r--guix/read-print.scm2
-rw-r--r--guix/scripts/challenge.scm11
-rw-r--r--guix/scripts/download.scm2
-rw-r--r--guix/scripts/edit.scm6
-rw-r--r--guix/scripts/environment.scm10
-rw-r--r--guix/scripts/import.scm2
-rw-r--r--guix/scripts/import/composer.scm107
-rw-r--r--guix/scripts/import/crate.scm24
-rw-r--r--guix/scripts/locate.scm26
-rw-r--r--guix/scripts/pack.scm96
-rw-r--r--guix/scripts/shell.scm7
-rw-r--r--guix/scripts/size.scm3
-rw-r--r--guix/scripts/style.scm2
-rwxr-xr-xguix/scripts/substitute.scm5
-rw-r--r--guix/scripts/system.scm31
-rw-r--r--guix/scripts/time-machine.scm91
-rw-r--r--guix/scripts/weather.scm61
-rw-r--r--guix/self.scm5
-rw-r--r--guix/store.scm18
-rw-r--r--guix/transformations.scm25
-rw-r--r--guix/ui.scm4
-rw-r--r--guix/utils.scm18
72 files changed, 3023 insertions, 448 deletions
diff --git a/guix/build-system/ant.scm b/guix/build-system/ant.scm
index e191fd3c99..84bf951fab 100644
--- a/guix/build-system/ant.scm
+++ b/guix/build-system/ant.scm
@@ -103,6 +103,7 @@
(build-target "jar")
(jar-name #f)
(main-class #f)
+ (use-java-modules? #f)
(test-include (list "**/*Test.java"))
(test-exclude (list "**/Abstract*.java"))
(source-dir "src")
@@ -131,6 +132,7 @@
#:build-target #$build-target
#:jar-name #$jar-name
#:main-class #$main-class
+ #:use-java-modules? #$use-java-modules?
#:test-include (list #$@test-include)
#:test-exclude (list #$@test-exclude)
#:source-dir #$source-dir
diff --git a/guix/build-system/cargo.scm b/guix/build-system/cargo.scm
index 912400a191..c029cc1dda 100644
--- a/guix/build-system/cargo.scm
+++ b/guix/build-system/cargo.scm
@@ -55,12 +55,18 @@
to NAME and VERSION."
(string-append crate-url name "/" version "/download"))
-(define (default-rust)
+(define (default-rust target)
"Return the default Rust package."
;; Lazily resolve the binding to avoid a circular dependency.
(let ((rust (resolve-interface '(gnu packages rust))))
(module-ref rust 'rust)))
+(define (default-rust-sysroot target)
+ "Return the default Rust sysroot for <target>."
+ ;; Lazily resolve the binding to avoid a circular dependency.
+ (let ((module (resolve-interface '(gnu packages rust))))
+ (module-ref module 'make-rust-sysroot)))
+
(define %cargo-utils-modules
;; Build-side modules imported by default.
`((guix build cargo-utils)
@@ -126,6 +132,69 @@ to NAME and VERSION."
#:graft? #f
#:guile-for-build guile))
+(define* (cargo-cross-build name
+ #:key
+ source target
+ build-inputs target-inputs host-inputs
+ (tests? #f)
+ (test-target #f)
+ (vendor-dir "guix-vendor")
+ (cargo-build-flags ''("--release"))
+ (cargo-test-flags ''("--release"))
+ (cargo-package-flags ''("--no-metadata" "--no-verify"))
+ (features ''())
+ (skip-build? #f)
+ (install-source? (not (target-mingw? target)))
+ (phases '%standard-phases)
+ (outputs '("out"))
+ (search-paths '())
+ (native-search-paths '())
+ (system (%current-system))
+ (guile #f)
+ (imported-modules %cargo-build-system-modules)
+ (modules '((guix build cargo-build-system)
+ (guix build utils))))
+ "Cross-build SOURCE using CARGO, and with INPUTS."
+
+ (define builder
+ (with-imported-modules imported-modules
+ #~(begin
+ (use-modules #$@(sexp->gexp modules))
+
+ (cargo-build #:name #$name
+ #:source #+source
+ #:target #+target
+ #:system #$system
+ #:test-target #$test-target
+ #:vendor-dir #$vendor-dir
+ #:cargo-build-flags #$(sexp->gexp cargo-build-flags)
+ #:cargo-test-flags #$(sexp->gexp cargo-test-flags)
+ #:cargo-package-flags #$(sexp->gexp cargo-package-flags)
+ #:features #$(sexp->gexp features)
+ #:skip-build? #$skip-build?
+ #:install-source? #$install-source?
+ #:tests? #$(and tests? (not skip-build?))
+ #:phases #$(if (pair? phases)
+ (sexp->gexp phases)
+ phases)
+ #:outputs #$(outputs->gexp outputs)
+ #:inputs (append #$(input-tuples->gexp host-inputs)
+ #+(input-tuples->gexp target-inputs))
+ #:native-inputs #+(input-tuples->gexp build-inputs)
+ #:make-dynamic-linker-cache? #f ;cross-compiling
+ #:search-paths '#$(sexp->gexp
+ (map search-path-specification->sexp
+ search-paths))
+ #:native-search-paths '#$(sexp->gexp
+ (map search-path-specification->sexp
+ native-search-paths))))))
+
+ (gexp->derivation name builder
+ #:system system
+ #:target target
+ #:graft? #f
+ #:guile-for-build guile))
+
(define (package-cargo-inputs p)
(apply
(lambda* (#:key (cargo-inputs '()) #:allow-other-keys)
@@ -235,7 +304,8 @@ any dependent crates. This can be a benefits:
(define* (lower name
#:key source inputs native-inputs outputs system target
- (rust (default-rust))
+ (rust (default-rust target))
+ (rust-sysroot (default-rust-sysroot target))
(cargo-inputs '())
(cargo-development-inputs '())
#:allow-other-keys
@@ -243,28 +313,49 @@ any dependent crates. This can be a benefits:
"Return a bag for NAME."
(define private-keywords
- '(#:target #:rust #:inputs #:native-inputs #:outputs
- #:cargo-inputs #:cargo-development-inputs))
-
- (and (not target) ;; TODO: support cross-compilation
- (bag
- (name name)
- (system system)
- (target target)
- (host-inputs `(,@(if source
- `(("source" ,source))
- '())
- ,@inputs
-
- ;; Keep the standard inputs of 'gnu-build-system'
- ,@(standard-packages)))
- (build-inputs `(("cargo" ,rust "cargo")
- ("rustc" ,rust)
- ,@(expand-crate-sources cargo-inputs cargo-development-inputs)
- ,@native-inputs))
- (outputs outputs)
- (build cargo-build)
- (arguments (strip-keyword-arguments private-keywords arguments)))))
+ `(#:rust #:inputs #:native-inputs #:outputs
+ #:cargo-inputs #:cargo-development-inputs
+ #:rust-sysroot
+ ,@(if target '() '(#:target))))
+
+ (bag
+ (name name)
+ (system system)
+ (target target)
+ (host-inputs `(,@(if source
+ `(("source" ,source))
+ '())
+
+ ;,@(if target '() inputs)
+ ,@(if target inputs '())
+
+ ,@(expand-crate-sources cargo-inputs cargo-development-inputs)))
+ (build-inputs `(("cargo" ,rust "cargo")
+ ("rustc" ,rust)
+
+ ,@native-inputs
+ ;,@(if target inputs '())
+ ,@(if target '() inputs)
+ ;,@inputs
+
+ ,@(if target
+ ;; Use the standard cross inputs of
+ ;; 'gnu-build-system'.
+ (standard-cross-packages target 'host)
+ '())
+ ;; Keep the standard inputs of 'gnu-build-system'
+ ,@(standard-packages)))
+ (target-inputs `(,@(if target
+ (standard-cross-packages target 'target)
+ '())
+
+ ;; This provides a separate sysroot for the regular rustc
+ ,@(if target
+ `(("rust-sysroot" ,(rust-sysroot target)))
+ '())))
+ (outputs outputs)
+ (build (if target cargo-cross-build cargo-build))
+ (arguments (strip-keyword-arguments private-keywords arguments))))
(define cargo-build-system
(build-system
diff --git a/guix/build-system/clojure.scm b/guix/build-system/clojure.scm
index fb897356bc..037fcaf21d 100644
--- a/guix/build-system/clojure.scm
+++ b/guix/build-system/clojure.scm
@@ -83,8 +83,8 @@
#:clojure #:jdk #:zip)))
(if target
- (error "No cross-compilation for clojure-build-system yet: LOWER"
- target) ; FIXME
+ #f ; FIXME: No cross-compilation for
+ ; clojure-build-system yet
(bag (name name)
(system system)
(host-inputs `(,@(if source
diff --git a/guix/build-system/composer.scm b/guix/build-system/composer.scm
new file mode 100644
index 0000000000..2ad7bbb36a
--- /dev/null
+++ b/guix/build-system/composer.scm
@@ -0,0 +1,166 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 build-system composer)
+ #:use-module (guix store)
+ #:use-module (guix utils)
+ #:use-module (guix derivations)
+ #:use-module (guix search-paths)
+ #:use-module (guix build-system)
+ #:use-module (guix build-system gnu)
+ #:use-module (guix gexp)
+ #:use-module (guix packages)
+ #:use-module (gnu packages)
+ #:use-module (ice-9 match)
+ #:use-module (srfi srfi-1)
+ #:export (%composer-build-system-modules
+ lower
+ composer-build
+ composer-build-system))
+
+;; Commentary:
+;;
+;; Standard build procedure for PHP packages using Composer. This is implemented
+;; as an extension of `gnu-build-system'.
+;;
+;; Code:
+
+(define (default-php)
+ "Return the default PHP package."
+
+ ;; Do not use `@' to avoid introducing circular dependencies.
+ (let ((module (resolve-interface '(gnu packages php))))
+ (module-ref module 'php)))
+
+(define (default-findclass)
+ "Return the default findclass script."
+ (search-auxiliary-file "findclass.php"))
+
+(define (default-composer-classloader)
+ "Return the default composer-classloader package."
+
+ ;; Do not use `@' to avoid introducing circular dependencies.
+ (let ((module (resolve-interface '(gnu packages php-xyz))))
+ (module-ref module 'composer-classloader)))
+
+(define %composer-build-system-modules
+ ;; Build-side modules imported by default.
+ `((guix build composer-build-system)
+ (guix build union)
+ ,@%gnu-build-system-modules))
+
+(define* (lower name
+ #:key source inputs native-inputs outputs system target
+ (php (default-php))
+ (composer-classloader (default-composer-classloader))
+ (findclass (default-findclass))
+ #:allow-other-keys
+ #:rest arguments)
+ "Return a bag for NAME."
+ (define private-keywords
+ '(#:target #:php #:composer-classloader #:findclass #:inputs #:native-inputs))
+
+ (and (not target) ;XXX: no cross-compilation
+ (bag
+ (name name)
+ (system system)
+ (host-inputs `(,@(if source
+ `(("source" ,source))
+ '())
+ ,@inputs
+
+ ;; Keep the standard inputs of 'gnu-build-system'.
+ ,@(standard-packages)))
+ (build-inputs `(("php" ,php)
+ ("findclass.php" ,findclass)
+ ("composer-classloader" ,composer-classloader)
+ ,@native-inputs))
+ (outputs outputs)
+ (build composer-build)
+ (arguments (strip-keyword-arguments private-keywords arguments)))))
+
+(define* (composer-build name inputs
+ #:key
+ guile source
+ (outputs '("out"))
+ (configure-flags ''())
+ (search-paths '())
+ (out-of-source? #t)
+ (composer-file "composer.json")
+ (tests? #t)
+ (test-target "test")
+ (test-flags ''())
+ (install-target "install")
+ (validate-runpath? #t)
+ (patch-shebangs? #t)
+ (strip-binaries? #t)
+ (strip-flags #~'("--strip-debug"))
+ (strip-directories #~'("lib" "lib64" "libexec"
+ "bin" "sbin"))
+ (phases '(@ (guix build composer-build-system)
+ %standard-phases))
+ (system (%current-system))
+ (imported-modules %composer-build-system-modules)
+ (modules '((guix build composer-build-system)
+ (guix build utils))))
+ "Build SOURCE using PHP, and with INPUTS. This assumes that SOURCE provides
+a 'composer.json' file as its build system."
+ (define guile-json
+ (module-ref (resolve-interface '(gnu packages guile))
+ 'guile-json-4))
+
+ (define builder
+ (with-extensions (list guile-json)
+ (with-imported-modules imported-modules
+ #~(begin
+ (use-modules #$@(sexp->gexp modules))
+
+ #$(with-build-variables inputs outputs
+ #~(composer-build
+ #:source #$source
+ #:system #$system
+ #:outputs %outputs
+ #:inputs %build-inputs
+ #:search-paths '#$(map search-path-specification->sexp
+ search-paths)
+ #:phases #$phases
+ #:out-of-source? #$out-of-source?
+ #:composer-file #$composer-file
+ #:tests? #$tests?
+ #:test-target #$test-target
+ #:test-flags #$test-flags
+ #:install-target #$install-target
+ #:validate-runpath? #$validate-runpath?
+ #:patch-shebangs? #$patch-shebangs?
+ #:strip-binaries? #$strip-binaries?
+ #:strip-flags #$strip-flags
+ #:strip-directories #$strip-directories))))))
+
+ (gexp->derivation name builder
+ #:system system
+ #:target #f
+ #:graft? #f
+ #:guile-for-build guile))
+
+(define composer-build-system
+ (build-system
+ (name 'composer)
+ (description "The standard Composer build system")
+ (lower lower)))
+
+;;; composer.scm ends here
diff --git a/guix/build-system/gnu.scm b/guix/build-system/gnu.scm
index c1aa187c42..cdbb547773 100644
--- a/guix/build-system/gnu.scm
+++ b/guix/build-system/gnu.scm
@@ -460,10 +460,13 @@ is one of `host' or `target'."
`(("cross-gcc" ,(gcc target
#:xbinutils (binutils target)
#:libc libc))
- ("cross-libc" ,libc)
+ ;; Some targets don't have a libc. (e.g. *-elf targets).
+ ,@(if libc
+ `(("cross-libc" ,libc))
+ '())
;; MinGW's libc doesn't have a "static" output.
- ,@(if (member "static" (package-outputs libc))
+ ,@(if (and libc (member "static" (package-outputs libc)))
`(("cross-libc:static" ,libc "static"))
'()))))))))
diff --git a/guix/build-system/guile.scm b/guix/build-system/guile.scm
index 1bd292e267..bd3bb1c870 100644
--- a/guix/build-system/guile.scm
+++ b/guix/build-system/guile.scm
@@ -88,7 +88,8 @@
(compile-flags %compile-flags)
(imported-modules %guile-build-system-modules)
(modules '((guix build guile-build-system)
- (guix build utils))))
+ (guix build utils)))
+ (substitutable? #t))
"Build SOURCE using Guile taken from the native inputs, and with INPUTS."
(define builder
(with-imported-modules imported-modules
@@ -114,6 +115,7 @@
#:system system
#:target #f
#:graft? #f
+ #:substitutable? substitutable?
#:guile-for-build guile)))
(define* (guile-cross-build name
@@ -133,7 +135,8 @@
(compile-flags %compile-flags)
(imported-modules %guile-build-system-modules)
(modules '((guix build guile-build-system)
- (guix build utils))))
+ (guix build utils)))
+ (substitutable? #t))
(define builder
(with-imported-modules imported-modules
#~(begin
@@ -173,6 +176,7 @@
#:system system
#:target target
#:graft? #f
+ #:substitutable? substitutable?
#:guile-for-build guile)))
(define guile-build-system
diff --git a/guix/build-system/meson.scm b/guix/build-system/meson.scm
index 7c617bffb0..bf9ca15ecc 100644
--- a/guix/build-system/meson.scm
+++ b/guix/build-system/meson.scm
@@ -49,11 +49,13 @@ for TRIPLET."
`((system . ,(cond ((target-hurd? triplet) "gnu")
((target-linux? triplet) "linux")
((target-mingw? triplet) "windows")
+ ((target-avr? triplet) "none")
(#t (error "meson: unknown operating system"))))
(cpu_family . ,(cond ((target-x86-32? triplet) "x86")
((target-x86-64? triplet) "x86_64")
((target-arm32? triplet) "arm")
((target-aarch64? triplet) "aarch64")
+ ((target-avr? triplet) "avr")
((target-mips64el? triplet) "mips64")
((target-powerpc? triplet)
(if (target-64bit? triplet)
@@ -66,6 +68,7 @@ for TRIPLET."
((target-x86-64? triplet) "x86_64")
((target-aarch64? triplet) "armv8-a")
((target-arm32? triplet) "armv7")
+ ((target-avr? triplet) "avr")
;; According to #mesonbuild on OFTC, there does not appear
;; to be an official-ish list of CPU types recognised by
;; Meson, the "cpu" field is not used by Meson itself and
@@ -89,6 +92,13 @@ TRIPLET."
(ld . ,(string-append triplet "-ld"))
(strip . ,(string-append triplet "-strip"))))
+(define (make-built-in-options-alist triplet)
+ (if (target-avr? triplet)
+ `((b_pie . #f)
+ (b_staticpic . #f)
+ (default_library . "static"))
+ '()))
+
(define (make-cross-file triplet)
(computed-file "cross-file"
(with-imported-modules '((guix build meson-configuration))
@@ -99,7 +109,9 @@ TRIPLET."
(write-section-header port "host_machine")
(write-assignments port '#$(make-machine-alist triplet))
(write-section-header port "binaries")
- (write-assignments port '#$(make-binaries-alist triplet))))))))
+ (write-assignments port '#$(make-binaries-alist triplet))
+ (write-section-header port "built-in options")
+ (write-assignments port '#$(make-built-in-options-alist triplet))))))))
(define %meson-build-system-modules
;; Build-side modules imported by default.
@@ -182,6 +194,7 @@ TRIPLET."
(imported-modules %meson-build-system-modules)
(modules '((guix build meson-build-system)
(guix build utils)))
+ (substitutable? #t)
allowed-references
disallowed-references)
"Build SOURCE using MESON, and with INPUTS, assuming that SOURCE
@@ -266,6 +279,7 @@ has a 'meson.build' file."
(imported-modules %meson-build-system-modules)
(modules '((guix build meson-build-system)
(guix build utils)))
+ (substitutable? #t)
allowed-references
disallowed-references)
"Cross-build SOURCE for TARGET using MESON, and with INPUTS, assuming that
diff --git a/guix/build-system/mix.scm b/guix/build-system/mix.scm
new file mode 100644
index 0000000000..1b04053d70
--- /dev/null
+++ b/guix/build-system/mix.scm
@@ -0,0 +1,186 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2023 Pierre-Henry Fröhring <contact@phfrohring.com>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+;; Commentary:
+;;
+;; Standard build procedure for Elixir packages using 'mix'. This is
+;; implemented as an extension of 'gnu-build-system'.
+;;
+;; Code:
+
+(define-module (guix build-system mix)
+ #:use-module (guix build mix-build-system)
+ #:use-module (guix build-system gnu)
+ #:use-module (guix build-system)
+ #:use-module (guix gexp)
+ #:use-module (guix monads)
+ #:use-module (guix packages)
+ #:use-module (guix search-paths)
+ #:use-module (guix store)
+ #:use-module (guix utils)
+ #:use-module (ice-9 match)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-26)
+ #:export (mix-build-system hexpm-uri))
+
+;; Lazily resolve bindings to avoid circular dependencies.
+(define (default-glibc-utf8-locales)
+ (let* ((base (resolve-interface '(gnu packages base))))
+ (module-ref base 'glibc-utf8-locales)))
+
+(define (default-elixir-hex)
+ (let ((elixir (resolve-interface '(gnu packages elixir))))
+ (module-ref elixir 'elixir-hex)))
+
+(define (default-rebar3)
+ (let ((erlang (resolve-interface '(gnu packages erlang))))
+ (module-ref erlang 'rebar3)))
+
+(define (default-elixir)
+ (let ((elixir (resolve-interface '(gnu packages elixir))))
+ (module-ref elixir 'elixir)))
+
+(define* (strip-prefix name #:optional (prefix "elixir-"))
+ "Return NAME without the prefix PREFIX."
+ (if (string-prefix? prefix name)
+ (string-drop name (string-length prefix))
+ name))
+
+(define (hexpm-uri name version)
+ "Return the URI where to fetch the sources of a Hex package NAME at VERSION.
+NAME is the name of the package which should look like: elixir-pkg-name-X.Y.Z
+See: https://github.com/hexpm/specifications/blob/main/endpoints.md"
+ ((compose
+ (cute string-append "https://repo.hex.pm/tarballs/" <> "-" version ".tar")
+ (cute string-replace-substring <> "-" "_")
+ strip-prefix)
+ name))
+
+;; A number of environment variables specific to the Mix build system are
+;; reflected here. They are documented at
+;; https://hexdocs.pm/mix/1.15.7/Mix.html#module-environment-variables. Other
+;; parameters located in mix.exs are defined at
+;; https://hexdocs.pm/mix/1.15.7/Mix.Project.html#module-configuration
+(define* (mix-build name
+ inputs
+ #:key
+ source
+ (tests? #t)
+ (mix-path #f) ;See MIX_PATH.
+ (mix-exs "mix.exs") ;See MIX_EXS.
+ (build-per-environment #t) ;See :build_per_environment.
+ (phases '%standard-phases)
+ (outputs '("out"))
+ (search-paths '())
+ (system (%current-system))
+ (guile #f)
+ (imported-modules `((guix build mix-build-system)
+ ,@%gnu-build-system-modules))
+ (modules '((guix build mix-build-system)
+ (guix build utils))))
+ "Build SOURCE using Elixir, and with INPUTS."
+
+ ;; Check the documentation of :build_per_environment here:
+ ;; https://hexdocs.pm/mix/1.15.7/Mix.Project.html#module-configuration And
+ ;; "Environments" here:
+ ;; https://hexdocs.pm/mix/1.15.7/Mix.html#module-environments
+ (define mix-environments
+ (if build-per-environment
+ `("prod" ,@(if tests? '("test") '()))
+ '("shared")))
+
+ (define builder
+ (with-imported-modules imported-modules
+ #~(begin
+
+ (use-modules #$@(sexp->gexp modules))
+
+ #$(with-build-variables inputs outputs
+ #~(mix-build #:name #$name
+ #:source #+source
+ #:system #$system
+ #:tests? #$tests?
+ #:mix-path #$mix-path
+ #:mix-exs #$mix-exs
+ #:mix-environments '#$mix-environments
+ #:build-per-environment #$build-per-environment
+ #:phases #$(if (pair? phases)
+ (sexp->gexp phases)
+ phases)
+ #:outputs %outputs
+ #:search-paths '#$(sexp->gexp
+ (map
+ search-path-specification->sexp
+ search-paths))
+ #:inputs
+ %build-inputs)))))
+
+ (mlet %store-monad ((guile (package->derivation (or guile (default-guile))
+ system
+ #:graft? #f)))
+ (gexp->derivation name
+ builder
+ #:system system
+ #:graft? #f ;consistent with 'gnu-build'
+ #:target #f
+ #:guile-for-build guile)))
+
+(define* (lower name
+ #:key
+ (elixir (default-elixir))
+ (elixir-hex (default-elixir-hex))
+ (glibc-utf8-locales (default-glibc-utf8-locales))
+ (inputs '())
+ (native-inputs '())
+ (propagated-inputs '())
+ (rebar3 (default-rebar3))
+ (tests? #t)
+ outputs
+ source
+ system
+ target
+ #:allow-other-keys #:rest arguments)
+ "Return a bag for NAME."
+ (let ((private-keywords
+ '(#:inputs #:native-inputs
+ #:outputs #:system #:target
+ #:elixir #:elixir-hex #:glibc-utf8-locales
+ #:rebar3 #:erlang))
+ (build-inputs
+ `(,@(standard-packages)
+ ("glibc-utf8-locales" ,glibc-utf8-locales)
+ ("erlang" ,(lookup-package-input elixir "erlang"))
+ ("rebar3" ,rebar3)
+ ("elixir" ,elixir)
+ ("elixir-hex" ,elixir-hex)
+ ,@inputs
+ ,@native-inputs)))
+ (bag (name name)
+ (system system)
+ (build-inputs build-inputs)
+ (host-inputs (if target inputs '()))
+ (outputs outputs)
+ (build mix-build)
+ (arguments (strip-keyword-arguments private-keywords arguments)))))
+
+(define mix-build-system
+ (build-system (name 'mix)
+ (description "The standard Mix build system")
+ (lower lower)))
+
+;;; mix.scm ends here
diff --git a/guix/build-system/perl.scm b/guix/build-system/perl.scm
index 7c6deb34bf..0d5493ab90 100644
--- a/guix/build-system/perl.scm
+++ b/guix/build-system/perl.scm
@@ -133,7 +133,9 @@ provides a `Makefile.PL' file as its build system."
search-paths))
#:make-maker? #$make-maker?
#:make-maker-flags #$make-maker-flags
- #:module-build-flags #$(sexp->gexp module-build-flags)
+ #:module-build-flags #$(if (pair? module-build-flags)
+ (sexp->gexp module-build-flags)
+ module-build-flags)
#:phases #$(if (pair? phases)
(sexp->gexp phases)
phases)
diff --git a/guix/build-system/r.scm b/guix/build-system/r.scm
index 657346bea3..7ab4db82b6 100644
--- a/guix/build-system/r.scm
+++ b/guix/build-system/r.scm
@@ -60,7 +60,7 @@ release corresponding to NAME and VERSION."
"/src/contrib/"
name "_" version ".tar.gz")
;; TODO: use %bioconductor-version from (guix import cran)
- (string-append "https://bioconductor.org/packages/3.17"
+ (string-append "https://bioconductor.org/packages/3.18"
type-url-part
"/src/contrib/"
name "_" version ".tar.gz"))))
diff --git a/guix/build-system/vim.scm b/guix/build-system/vim.scm
new file mode 100644
index 0000000000..dddf7ea14b
--- /dev/null
+++ b/guix/build-system/vim.scm
@@ -0,0 +1,170 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2022 Jonathan Scoresby <me@jonscoresby.com>
+;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il>
+;;;
+;;; 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 build-system vim)
+ #:use-module (guix store)
+ #:use-module (guix utils)
+ #:use-module (guix gexp)
+ #:use-module (guix monads)
+ #:use-module (guix packages)
+ #:use-module (guix search-paths)
+ #:use-module (guix build-system)
+ #:use-module (guix build-system copy)
+ #:use-module (guix build-system gnu)
+ #:export (%vim-build-system-modules vim-build vim-build-system))
+
+;; Commentary:
+;;
+;; Standard package installer for vim and neovim plugins.
+;; This is implemented as an extension of the `copy-build-system'
+;; and takes advantage of vim and neovim's built-in package manager.
+;; It extends the installation procedure from the copy-build-system
+;; to put files in the correct place and then generates help tags.
+;;
+;; Code:
+
+(define %vim-build-system-modules
+ ;; Build-side modules imported by default.
+ `((guix build vim-build-system)
+ ,@%copy-build-system-modules))
+
+(define (default-vim)
+ "Return the default Vim package."
+ ;; Lazily resolve the binding to avoid a circular dependency.
+ (let ((vim (resolve-interface '(gnu packages vim))))
+ (module-ref vim 'vim)))
+
+(define (default-neovim)
+ "Return the default Neovim package."
+ (let ((vim (resolve-interface '(gnu packages vim))))
+ (module-ref vim 'neovim)))
+
+(define* (lower name
+ #:key source
+ inputs
+ native-inputs
+ outputs
+ system
+ target
+ (vim? #f)
+ (neovim? #f)
+ (plugin-name name)
+ (vim (default-vim))
+ (neovim (default-neovim))
+ #:allow-other-keys #:rest arguments)
+ "Return a bag for NAME."
+ (let* ((private-keywords '(#:target #:vim #:neovim #:inputs #:native-inputs))
+ (vim? (or (string-prefix? "vim-" name)
+ vim?))
+ (neovim? (or (string-prefix? "neovim-" name)
+ neovim?))
+ (vim-inputs (append (if vim?
+ `(("vim" ,vim))
+ '())
+ (if neovim?
+ `(("neovim" ,neovim))
+ '())))
+ (vim-arguments (append arguments
+ `(#:vim? ,vim?
+ #:neovim? ,neovim?))))
+ (bag (name name)
+ (system system)
+ (host-inputs `(,@(if source
+ `(("source" ,source))
+ '()) ,@inputs
+
+ ;; Keep the standard inputs of 'gnu-build-system'.
+ ,@(standard-packages)))
+ (build-inputs `(,@vim-inputs ,@native-inputs))
+ (outputs outputs)
+ (build vim-build)
+ (arguments (strip-keyword-arguments private-keywords vim-arguments)))))
+
+(define* (vim-build name inputs
+ #:key guile
+ source
+ (vim? #f)
+ (neovim? #f)
+ (mode "start")
+ (plugin-name name)
+ (install-plan ''())
+ (phases '(@ (guix build vim-build-system) %standard-phases))
+ (outputs '("out"))
+ (out-of-source? #t)
+ (tests? #t)
+ (validate-runpath? #t)
+ (patch-shebangs? #t)
+ (strip-binaries? #t)
+ (strip-flags %strip-flags)
+ (strip-directories %strip-directories)
+ (search-paths '())
+ (system (%current-system))
+ (substitutable? #t)
+ (imported-modules %vim-build-system-modules)
+ (modules '((guix build vim-build-system)
+ (guix build utils))))
+
+ (define build
+ (with-imported-modules imported-modules
+ #~(begin
+ (use-modules #$@modules)
+ #$(with-build-variables inputs outputs
+ #~(vim-build #:name #$name
+ #:vim? #$vim?
+ #:neovim? #$neovim?
+ #:mode #$mode
+ #:plugin-name #$plugin-name
+ #:install-plan #$(if (pair? install-plan)
+ (sexp->gexp install-plan)
+ install-plan)
+ #:source #+source
+ #:system #$system
+ #:phases #$(if (pair? phases)
+ (sexp->gexp phases)
+ phases)
+ #:outputs %outputs
+ #:search-paths '#$(sexp->gexp
+ (map search-path-specification->sexp
+ search-paths))
+ #:inputs %build-inputs
+ #:out-of-source? #$out-of-source?
+ #:tests? #$tests?
+ #:validate-runpath? #$validate-runpath?
+ #:patch-shebangs? #$patch-shebangs?
+ #:strip-binaries? #$strip-binaries?
+ #:strip-flags #$strip-flags
+ #:strip-directories #$strip-directories)))))
+
+ (mlet %store-monad
+ ((guile (package->derivation (or guile (default-guile))
+ system #:graft? #f)))
+ (gexp->derivation name
+ build
+ #:system system
+ #:target #f
+ #:graft? #f
+ #:substitutable? substitutable?
+ #:guile-for-build guile)))
+
+(define vim-build-system
+ (build-system (name 'vim)
+ (description "The standard Vim build system")
+ (lower lower)))
+
+;;; vim.scm ends here
diff --git a/guix/build-system/zig.scm b/guix/build-system/zig.scm
index 16b8a712cc..1fa4782a2e 100644
--- a/guix/build-system/zig.scm
+++ b/guix/build-system/zig.scm
@@ -39,7 +39,6 @@
(define %zig-build-system-modules
;; Build-side modules imported by default.
`((guix build zig-build-system)
- (guix build syscalls)
,@%gnu-build-system-modules))
(define* (zig-build name inputs
@@ -84,6 +83,79 @@
#:system system
#:guile-for-build guile)))
+(define* (zig-cross-build name
+ #:key
+ source target
+ build-inputs target-inputs host-inputs
+ (phases '%standard-phases)
+ (outputs '("out"))
+ (search-paths '())
+ (native-search-paths '())
+ (tests? #t)
+ (test-target #f)
+ (zig-build-flags ''())
+ (zig-test-flags ''())
+ (zig-destdir "out")
+ (zig-test-destdir "test-out")
+ (zig-release-type #f)
+ (system (%current-system))
+ (guile #f)
+ (imported-modules %zig-build-system-modules)
+ (modules '((guix build zig-build-system)
+ (guix build utils))))
+ "Build SOURCE using Zig, and with INPUTS."
+ (define builder
+ (with-imported-modules imported-modules
+ #~(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))
+
+ (zig-build #:name #$name
+ #:source #+source
+ #:system #$system
+ #:phases #$phases
+ #:outputs %outputs
+ #:target #$target
+ #:test-target #$test-target
+ #:inputs %build-target-inputs
+ #:native-inputs %build-host-inputs
+ #:search-paths '#$(map search-path-specification->sexp
+ search-paths)
+ #:native-search-paths '#$(map
+ search-path-specification->sexp
+ native-search-paths)
+ #:zig-build-flags #$zig-build-flags
+ #:zig-test-flags #$zig-test-flags
+ #:zig-release-type #$zig-release-type
+ #:zig-destdir #$zig-destdir
+ #:zig-test-destdir #$zig-test-destdir
+ #:tests? #$tests?
+ #:search-paths '#$(sexp->gexp
+ (map search-path-specification->sexp
+ search-paths))))))
+
+ (mlet %store-monad ((guile (package->derivation (or guile (default-guile))
+ system #:graft? #f)))
+ (gexp->derivation name builder
+ #:system system
+ #:target target
+ #:graft? #f
+ #:substitutable? substitutable?
+ #:guile-for-build guile)))
+
+
(define* (lower name
#:key source inputs native-inputs outputs system target
(zig (default-zig))
@@ -94,27 +166,30 @@
(define private-keywords
'(#:target #:zig #:inputs #:native-inputs #:outputs))
- ;; TODO: support cross-compilation
- ;; It's as simple as adding some build flags to `zig-build-flags`
- ;; -Dtarget=aarch64-linux-musl, for example.
- (and (not target)
- (bag
- (name name)
- (system system)
- (target target)
- (host-inputs `(,@(if source
- `(("source" ,source))
- '())
- ,@inputs
-
- ;; Keep the standard inputs of 'gnu-build-system'
- ;; TODO: do we need this?
- ,@(standard-packages)))
- (build-inputs `(("zig" ,zig)
- ,@native-inputs))
- (outputs outputs)
- (build zig-build)
- (arguments (strip-keyword-arguments private-keywords arguments)))))
+ (bag
+ (name name)
+ (system system)
+ (target target)
+ (build-inputs `(,@(if source
+ `(("source" ,source))
+ '())
+ ,@`(("zig" ,zig))
+ ,@native-inputs
+ ,@(if target '() inputs)
+ ,@(if target
+ ;; Use the standard cross inputs of
+ ;; 'gnu-build-system'.
+ (standard-cross-packages target 'host)
+ '())
+ ;; Keep the standard inputs of 'gnu-build-system'.
+ ,@(standard-packages)))
+ (host-inputs (if target inputs '()))
+ (target-inputs (if target
+ (standard-cross-packages target 'target)
+ '()))
+ (outputs outputs)
+ (build (if target zig-cross-build zig-build))
+ (arguments (strip-keyword-arguments private-keywords arguments))))
(define zig-build-system
(build-system
diff --git a/guix/build/ant-build-system.scm b/guix/build/ant-build-system.scm
index d29912bf59..ced34177f4 100644
--- a/guix/build/ant-build-system.scm
+++ b/guix/build/ant-build-system.scm
@@ -37,6 +37,7 @@
(define* (default-build.xml jar-name prefix #:optional
(source-dir ".") (test-dir "./test") (main-class #f)
+ (use-java-modules? #f)
(test-include '("**/*Test.java"))
(test-exclude '("**/Abstract*Test.java")))
"Create a simple build.xml with standard targets for Ant."
@@ -65,7 +66,7 @@
(value "first")))
(property (@ (environment "env")))
(path (@ (id "classpath"))
- (pathelement (@ (location "${env.CLASSPATH}"))))
+ (pathelement (@ (path "${env.CLASSPATH}"))))
(target (@ (name "manifest"))
(mkdir (@ (dir "${manifest.dir}")))
@@ -79,18 +80,30 @@
(mkdir (@ (dir "${classes.dir}")))
(javac (@ (includeantruntime "false")
(srcdir ,source-dir)
- (destdir "${classes.dir}")
- (classpath (@ (refid "classpath"))))))
+ (destdir "${classes.dir}"))
+ ,(if use-java-modules?
+ `((modulepath (@ (refid "classpath"))))
+ '())
+ (classpath (@ (refid "classpath")))))
(target (@ (name "compile-tests"))
(mkdir (@ (dir "${test.classes.dir}")))
(javac (@ (includeantruntime "false")
(srcdir ,test-dir)
(destdir "${test.classes.dir}"))
- (classpath
- (pathelement (@ (path "${env.CLASSPATH}")))
- (pathelement (@ (location "${classes.dir}")))
- (pathelement (@ (location "${test.classes.dir}"))))))
+ ,(if use-java-modules?
+ `((classpath
+ (pathelement
+ (@ (path "${env.CLASSPATH}")))
+ (pathelement
+ (@ (location "${classes.dir}")))
+ (pathelement
+ (@ (location "${test.classes.dir}")))))
+ '())
+ (classpath
+ (pathelement (@ (path "${env.CLASSPATH}")))
+ (pathelement (@ (location "${classes.dir}")))
+ (pathelement (@ (location "${test.classes.dir}"))))))
(target (@ (name "check")
(depends "compile-tests"))
@@ -156,13 +169,15 @@ to the default GNU unpack strategy."
(source-dir "src")
(test-dir "src/test")
(main-class #f)
+ (use-java-modules? #f)
(test-include '("**/*Test.java"))
(test-exclude '("**/Abstract*.java")) #:allow-other-keys)
(when jar-name
(default-build.xml jar-name
(string-append (assoc-ref outputs "out")
"/share/java")
- source-dir test-dir main-class test-include test-exclude))
+ source-dir test-dir main-class use-java-modules?
+ test-include test-exclude))
(setenv "JAVA_HOME" (assoc-ref inputs "jdk"))
(setenv "CLASSPATH" (generate-classpath inputs))
#t)
diff --git a/guix/build/cargo-build-system.scm b/guix/build/cargo-build-system.scm
index 505c0b4b01..ffb2ec898e 100644
--- a/guix/build/cargo-build-system.scm
+++ b/guix/build/cargo-build-system.scm
@@ -119,6 +119,7 @@ libraries or executables."
(error "Possible pre-generated files found:" pregenerated-files))))
(define* (configure #:key inputs
+ target
(vendor-dir "guix-vendor")
#:allow-other-keys)
"Vendor Cargo.toml dependencies as guix inputs."
@@ -146,27 +147,75 @@ libraries or executables."
(invoke "tar" "xf" path "-C" crate-dir "--strip-components" "1")))))
inputs)
- ;; Configure cargo to actually use this new directory.
+ ;; For cross-building
+ (when target
+ (setenv "CARGO_BUILD_TARGET"
+ ;; Can this be replaced with platform-rust-architecture?
+ ;; Keep this synchronized with (guix platforms *)
+ (match target
+ ("aarch64-linux-gnu" "aarch64-unknown-linux-gnu")
+ ("arm-linux-gnueabihf" "armv7-unknown-linux-gnueabihf")
+ ("i686-linux-gnu" "i686-unknown-linux-gnu")
+ ("mips64el-linux-gnu" "mips64el-unknown-linux-gnuabi64")
+ ("powerpc-linux-gnu" "powerpc-unknown-linux-gnu")
+ ("powerpc64-linux-gnu" "powerpc64-unknown-linux-gnu")
+ ("powerpc64le-linux-gnu" "powerpc64le-unknown-linux-gnu")
+ ("riscv64-linux-gnu" "riscv64gc-unknown-linux-gnu")
+ ("x86_64-linux-gnu" "x86_64-unknown-linux-gnu")
+ ("i586-pc-gnu" "i686-unknown-hurd-gnu")
+ ("i686-w64-mingw32" "i686-pc-windows-gnu")
+ ("x86_64-w64-mingw32" "x86_64-pc-windows-gnu")
+ (else #f)))
+ (setenv "RUSTFLAGS" (string-append
+ (or (getenv "RUSTFLAGS") "")
+ " --sysroot " (assoc-ref inputs "rust-sysroot")))
+
+ (setenv "PKG_CONFIG" (string-append target "-pkg-config"))
+
+ ;; We've removed all the bundled libraries, don't look for them.
+ (setenv "WINAPI_NO_BUNDLED_LIBRARIES" "1")
+
+ ;; Prevent targeting the build machine.
+ (setenv "CRATE_CC_NO_DEFAULTS" "1"))
+
+ ;; Configure cargo to actually use this new directory with all the crates.
(setenv "CARGO_HOME" (string-append (getcwd) "/.cargo"))
(mkdir-p ".cargo")
+ ;; Not .cargo/config.toml, rustc/cargo will generate .cargo/config otherwise.
(let ((port (open-file ".cargo/config" "w" #:encoding "utf-8")))
- (display "
+ ;; Placed here so it doesn't cause random rebuilds. Neither of these work.
+ ;; sysroot = '" (assoc-ref inputs "rust-sysroot") "'
+ ;; rustflags = ['--sysroot', '" (assoc-ref inputs "rust-sysroot") "']
+ (when target
+ (display (string-append "
+[target." (getenv "CARGO_BUILD_TARGET") "]
+linker = '" target "-gcc'
+
+[build]
+target = ['" (getenv "CARGO_BUILD_TARGET") "']") port))
+ (display (string-append "
[source.crates-io]
replace-with = 'vendored-sources'
[source.vendored-sources]
-directory = '" port)
- (display (string-append (getcwd) "/" vendor-dir) port)
- (display "'
-" port)
+directory = '" vendor-dir "'") port)
(close-port port))
;; Lift restriction on any lints: a crate author may have decided to opt
;; into stricter lints (e.g. #![deny(warnings)]) during their own builds
;; but we don't want any build failures that could be caused later by
;; upgrading the compiler for example.
- (setenv "RUSTFLAGS" "--cap-lints allow")
- (setenv "CC" (string-append (assoc-ref inputs "gcc") "/bin/gcc"))
+ (setenv "RUSTFLAGS" (string-append (or (getenv "RUSTFLAGS") "")
+ " --cap-lints allow"))
+
+ (if (assoc-ref inputs "cross-gcc")
+ (begin
+ (setenv "HOST_CC" "gcc")
+ (setenv "TARGET_CC" (string-append target "-gcc"))
+ (setenv "TARGET_AR" (string-append target "-ar"))
+ (setenv "TARGET_PKG_CONFIG" (string-append target "-pkg-config")))
+ (setenv "CC" (string-append (assoc-ref inputs "gcc") "/bin/gcc")))
+
(setenv "LIBGIT2_SYS_USE_PKG_CONFIG" "1")
(setenv "LIBSSH2_SYS_USE_PKG_CONFIG" "1")
(when (assoc-ref inputs "openssl")
@@ -264,7 +313,11 @@ directory = '" port)
(unless (eq? (stat:type s) 'symlink)
(utime file 0 0 0 0))))
(find-files dir #:directories? #t))
+
(apply invoke "tar" "czf" (string-append dir ".crate")
+ ;; avoid non-determinism in the archive
+ "--sort=name" "--mtime=@0"
+ "--owner=root:0" "--group=root:0"
(find-files dir #:directories? #t))
(delete-file-recursively dir)))
(find-files "." "\\.crate$")))))
diff --git a/guix/build/composer-build-system.scm b/guix/build/composer-build-system.scm
new file mode 100644
index 0000000000..8896384e0a
--- /dev/null
+++ b/guix/build/composer-build-system.scm
@@ -0,0 +1,301 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;; Copyright © 2023 Nicolas Graves <ngraves@ngraves.fr>
+;;;
+;;; 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 build composer-build-system)
+ #:use-module ((guix build gnu-build-system) #:prefix gnu:)
+ #:use-module (guix build utils)
+ #:use-module (ice-9 match)
+ #:use-module (json)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-26)
+ #:export (%standard-phases
+ composer-build))
+
+;; Commentary:
+;;
+;; Builder-side code of the standard composer build procedure.
+;;
+;; Code:
+
+(define (json->require dict)
+ (if dict
+ (let loop ((result '()) (require dict))
+ (match require
+ (() result)
+ ((((? (cut string-contains <> "/") name) . _)
+ require ...)
+ (loop (cons name result) require))
+ ((_ require ...) (loop result require))
+ (_ result)))
+ '()))
+
+(define (if-specified-to-list fn)
+ (match-lambda
+ ((? unspecified?) '())
+ (arg (fn arg))
+ (_ '())))
+
+(define-json-mapping <composer-autoload> make-composer-autoload
+ composer-autoload?
+ json->composer-autoload
+ (psr-4 composer-autoload-psr-4 "psr-4"
+ (match-lambda
+ ((? unspecified?) '())
+ ((? (lambda (al)
+ (and (list? al) (pair? (car al)) (vector? (cdar al)))) al)
+ (append-map
+ (lambda (vect-el)
+ (list (cons (caar al) vect-el)))
+ (vector->list (cdar al))))
+ ((? list? l) l)
+ (_ '())))
+ (psr-0 composer-autoload-psr-0 "psr-0" (if-specified-to-list identity))
+ (classmap composer-autoload-classmap "classmap"
+ (if-specified-to-list vector->list))
+ (files composer-autoload-files "files"
+ (if-specified-to-list vector->list)))
+
+(define-json-mapping <composer-package> make-composer-package composer-package?
+ json->composer-package
+ (name composer-package-name)
+ (autoload composer-package-autoload "autoload"
+ (if-specified-to-list json->composer-autoload))
+ (autoload-dev composer-package-autoload-dev "autoload-dev"
+ (if-specified-to-list json->composer-autoload))
+ (require composer-package-require "require" json->require)
+ (dev-require composer-package-dev-require "require-dev" json->require)
+ (scripts composer-package-scripts "scripts"
+ (if-specified-to-list identity))
+ (binaries composer-package-binaries "bin"
+ (if-specified-to-list vector->list)))
+
+(define* (read-package-data #:key (filename "composer.json"))
+ (call-with-input-file filename
+ (lambda (port)
+ (json->composer-package (json->scm port)))))
+
+(define* (create-test-autoload #:key composer-file inputs outputs tests?
+ #:allow-other-keys)
+ "Create the autoload.php file for tests. This is a standalone phase so that
+the autoload.php file can be edited before the check phase."
+ (when tests?
+ (mkdir-p "vendor")
+ (create-autoload (string-append (getcwd) "/vendor") composer-file
+ inputs #:dev-dependencies? #t)))
+
+(define (find-bin script inputs)
+ (search-input-file inputs
+ (string-append
+ "bin/"
+ (string-drop script (string-length "vendor/bin/")))))
+
+(define* (check #:key composer-file inputs
+ tests? test-target test-flags #:allow-other-keys)
+ "Test the given package.
+Please note that none of the PHP packages at the time of the rewrite of the
+build-system did use the test-script field. This means that the @code{match
+test-script} part is not tested on a real example and relies on the original
+implementation."
+ (if tests?
+ (let* ((package-data (read-package-data #:filename composer-file))
+ (scripts (composer-package-scripts package-data))
+ (test-script (assoc-ref scripts test-target)))
+ (match test-script
+ ((? string? bin)
+ (let ((command (find-bin bin inputs)))
+ (unless (zero? (apply system command test-flags))
+ (throw 'failed-command command))))
+ (('@ (? string? bins) ...)
+ (for-each
+ (lambda (c)
+ (let ((command (find-bin c inputs)))
+ (unless (zero? (apply system command test-flags))
+ (throw 'failed-command command))))
+ bins))
+ (_ (if (file-exists? "phpunit.xml.dist")
+ (apply invoke
+ (with-exception-handler
+ (lambda (exn)
+ (if (search-error? exn)
+ (error "\
+Missing php-phpunit-phpunit native input.~%")
+ (raise exn)))
+ (lambda ()
+ (search-input-file (or inputs '()) "bin/phpunit")))
+ test-flags))
+ (format #t "No test suite found.~%"))))
+ (format #t "Test suite not run.~%")))
+
+(define* (create-autoload vendor composer-file inputs #:key dev-dependencies?)
+ "creates an autoload.php file that sets up the class locations for this package,
+so it can be autoloaded by PHP when the package classes are required."
+ (with-output-to-file (string-append vendor "/autoload.php")
+ (lambda _
+ (display (string-append
+ "<?php
+// autoload.php @generated by Guix
+$psr4map = $classmap = array();
+require_once '" vendor "/autoload_conf.php';
+require_once '" (assoc-ref inputs "composer-classloader") "/share/web/composer/ClassLoader.php';
+$loader = new \\Composer\\Autoload\\ClassLoader();
+foreach ($psr4map as $namespace => $paths) {
+ foreach ($paths as $path) {
+ $loader->addPsr4($namespace, $path);
+ }
+}
+$loader->addClassMap($classmap);
+$loader->register();
+"))))
+ ;; Now, create autoload_conf.php that contains the actual data, as a set
+ ;; of arrays
+ (let* ((package-data (read-package-data #:filename composer-file))
+ (autoload (composer-package-autoload package-data))
+ (autoload-dev (composer-package-autoload-dev package-data))
+ (dependencies (composer-package-require package-data))
+ (dependencies-dev (composer-package-dev-require package-data)))
+ (with-output-to-file (string-append vendor "/autoload_conf.php")
+ (lambda _
+ (format #t "<?php~%")
+ (format #t "// autoload_conf.php @generated by Guix~%")
+ (force-output)
+ (for-each
+ (match-lambda
+ ((key . value)
+ (let ((vals (if (list? value)
+ (reverse value)
+ (list value))))
+ (apply
+ format
+ #t
+ (string-append
+ "$psr4map['~a'][] = ["
+ (string-join
+ (make-list (length vals) "'~a/../~a'") ",")
+ "];~%")
+ (cons* (string-join (string-split key #\\) "\\\\")
+ (append-map (lambda (v) (list vendor v)) vals)))))
+ (_ (format #t "")))
+ (delete-duplicates
+ (append
+ (composer-autoload-psr-4 autoload)
+ (if (and dev-dependencies? (not (null? autoload-dev)))
+ (composer-autoload-psr-4 autoload-dev)
+ '()))
+ '()))
+ (for-each
+ (lambda (psr0)
+ (match psr0
+ ((key . value)
+ (format #t "$psr4map['~a'][] = ['~a/../~a/~a'];~%"
+ (string-join (string-split key #\\) "\\\\")
+ vendor
+ value
+ (string-join (string-split key #\\) "/")))
+ (_ (format #t ""))))
+ (append
+ (composer-autoload-psr-0 autoload)
+ (if (and dev-dependencies? (not (null? autoload-dev)))
+ (composer-autoload-psr-0 autoload-dev)
+ '())))
+ (for-each
+ (lambda (classmap)
+ (for-each
+ (lambda (file)
+ (invoke "php" (assoc-ref inputs "findclass.php")
+ "-i" (string-append vendor "/..") "-f" file))
+ (find-files classmap ".(php|hh|inc)$")))
+ (append
+ (composer-autoload-classmap autoload)
+ (if (and dev-dependencies? (not (null? autoload-dev)))
+ (composer-autoload-classmap autoload-dev)
+ '())))
+ (for-each
+ (lambda (file)
+ (format #t "require_once '~a/../~a';~%" vendor file))
+ (append
+ (composer-autoload-files autoload)
+ (if (and dev-dependencies? (not (null? autoload-dev)))
+ (composer-autoload-files autoload-dev)
+ '())))
+ (for-each
+ (lambda (dep)
+ (format
+ #t "require_once '~a';~%"
+ (search-input-file
+ inputs
+ (string-append "/share/web/" dep "/vendor/autoload_conf.php"))))
+ dependencies)
+ ;; Also add native-inputs that are not necessarily given in the
+ ;; composer.json. This allows to simply add a package in tests by
+ ;; adding it in native-inputs, without the need to patch composer.json.
+ (for-each
+ (match-lambda
+ ((name . loc)
+ (match (find-files loc "autoload_conf\\.php$")
+ (() #t)
+ (((? string? conf) . ())
+ (format #t "require_once '~a';~%" conf))
+ (_ #t)))
+ (_ #t))
+ (or inputs '()))))))
+
+(define* (install #:key inputs outputs composer-file #:allow-other-keys)
+ "Install the given package."
+ (let* ((out (assoc-ref outputs "out"))
+ (package-data (read-package-data #:filename composer-file))
+ (name (composer-package-name package-data))
+ (php-dir (string-append out "/share/web/" name))
+ (bin-dir (string-append php-dir "/vendor/bin"))
+ (bin (string-append out "/bin"))
+ (binaries (composer-package-binaries package-data)))
+ (mkdir-p php-dir)
+ (copy-recursively "." php-dir)
+ (mkdir-p (string-append php-dir "/vendor"))
+ (when binaries
+ (mkdir-p bin-dir)
+ (mkdir-p bin)
+ (for-each
+ (lambda (file)
+ (let ((installed-file (string-append bin-dir "/" (basename file)))
+ (bin-file (string-append bin "/" (basename file)))
+ (original-file (string-append php-dir "/" file)))
+ (symlink original-file installed-file)
+ (symlink original-file bin-file)))
+ binaries))
+ (create-autoload (string-append php-dir "/vendor")
+ composer-file inputs)))
+
+(define %standard-phases
+ ;; Everything is as with the GNU Build System except for the `configure'
+ ;; , `build', `check' and `install' phases.
+ (modify-phases gnu:%standard-phases
+ (delete 'bootstrap)
+ (delete 'configure)
+ (delete 'build)
+ (delete 'check)
+ (replace 'install install)
+ (add-after 'install 'check check)
+ (add-after 'install 'create-test-autoload create-test-autoload)))
+
+(define* (composer-build #:key inputs (phases %standard-phases)
+ #:allow-other-keys #:rest args)
+ "Build the given package, applying all of PHASES in order."
+ (apply gnu:gnu-build #:inputs inputs #:phases phases args))
+
+;;; composer-build-system.scm ends here
diff --git a/guix/build/git.scm b/guix/build/git.scm
index 0ff263c81b..867cade2c4 100644
--- a/guix/build/git.scm
+++ b/guix/build/git.scm
@@ -1,5 +1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2014, 2016, 2019, 2023 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -33,10 +34,13 @@
;;; Code:
(define* (git-fetch url commit directory
- #:key (git-command "git") recursive?)
+ #:key (git-command "git")
+ lfs? recursive?)
"Fetch COMMIT from URL into DIRECTORY. COMMIT must be a valid Git commit
-identifier. When RECURSIVE? is true, all the sub-modules of URL are fetched,
-recursively. Return #t on success, #f otherwise."
+identifier. When LFS? is true, configure Git to also fetch Large File
+Storage (LFS) files; it assumes that the @code{git-lfs} extension is available
+in the environment. When RECURSIVE? is true, all the sub-modules of URL are
+fetched, recursively. Return #t on success, #f otherwise."
;; Disable TLS certificate verification. The hash of the checkout is known
;; in advance anyway.
@@ -57,6 +61,11 @@ recursively. Return #t on success, #f otherwise."
(with-directory-excursion directory
(invoke git-command "init" "--initial-branch=main")
(invoke git-command "remote" "add" "origin" url)
+
+ (when lfs?
+ (setenv "HOME" "/tmp")
+ (invoke git-command "lfs" "install"))
+
(if (zero? (system* git-command "fetch" "--depth" "1" "origin" commit))
(invoke git-command "checkout" "FETCH_HEAD")
(begin
@@ -81,11 +90,13 @@ recursively. Return #t on success, #f otherwise."
(define* (git-fetch-with-fallback url commit directory
- #:key (git-command "git") recursive?)
+ #:key (git-command "git")
+ lfs? recursive?)
"Like 'git-fetch', fetch COMMIT from URL into DIRECTORY, but fall back to
alternative methods when fetching from URL fails: attempt to download a nar,
and if that also fails, download from the Software Heritage archive."
(or (git-fetch url commit directory
+ #:lfs? lfs?
#:recursive? recursive?
#:git-command git-command)
(download-nar directory)
diff --git a/guix/build/guile-build-system.scm b/guix/build/guile-build-system.scm
index 32a431d347..e7e7f2d0be 100644
--- a/guix/build/guile-build-system.scm
+++ b/guix/build/guile-build-system.scm
@@ -28,6 +28,7 @@
#:use-module (ice-9 format)
#:use-module (guix build utils)
#:export (target-guile-effective-version
+ target-guile-scm+go
%standard-phases
guile-build))
@@ -44,7 +45,17 @@ Return #false if it cannot be determined."
(string? line)
line)))
-(define (file-sans-extension file) ;TODO: factorize
+(define* (target-guile-scm+go output #:optional guile)
+ "Return paths under `output' for scm and go files for effective version of
+GUILE or whichever `guile' is in $PATH. Raises an error if they cannot be
+determined."
+ (let* ((version (or (target-guile-effective-version guile)
+ (error "Cannot determine the effective target guile version.")))
+ (scm (string-append output "/share/guile/site/" version))
+ (go (string-append output "/lib/guile/" version "/site-ccache")))
+ (values scm go)))
+
+(define (file-sans-extension file) ;TODO: factorize
"Return the substring of FILE without its extension, if any."
(let ((dot (string-rindex file #\.)))
(if dot
diff --git a/guix/build/minetest-build-system.scm b/guix/build/minetest-build-system.scm
index 4a7a87ab83..3bf083e004 100644
--- a/guix/build/minetest-build-system.scm
+++ b/guix/build/minetest-build-system.scm
@@ -126,7 +126,8 @@ If it is unknown, make an educated guess."
(/ total-old-size (expt 1024 2))
(/ total-new-size (expt 1024 2)))))))
-(define name-regexp (make-regexp "^name[ ]*=(.+)$"))
+(define name-regexp
+ (make-regexp "^name[[:space:]]*=[[:space:]]*([[:graph:]]+)[[:space:]]*$"))
(define* (read-mod-name mod.conf #:optional not-found)
"Read the name of a mod from MOD.CONF. If MOD.CONF
diff --git a/guix/build/mix-build-system.scm b/guix/build/mix-build-system.scm
new file mode 100644
index 0000000000..fe2e36d184
--- /dev/null
+++ b/guix/build/mix-build-system.scm
@@ -0,0 +1,161 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2023 Pierre-Henry Fröhring <contact@phfrohring.com>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+;; Commentary:
+;;
+;; Code:
+
+(define-module (guix build mix-build-system)
+ #:use-module ((guix build gnu-build-system) #:prefix gnu:)
+ #:use-module (guix build utils)
+ #:use-module (ice-9 ftw)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 regex)
+ #:use-module (ice-9 string-fun)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-26)
+ #:use-module (srfi srfi-71)
+ #:export (mix-build
+ %standard-phases))
+
+;; The Elixir version is constant as soon as it is computable from the current
+;; execution. It is a X.Y string where X and Y are respectively the major and
+;; minor version number of the Elixir used in the build.
+(define %elixir-version (make-parameter "X.Y"))
+
+(define* (elixir-libdir path #:optional (version (%elixir-version)))
+ "Return the path where all libraries under PATH for a specified Elixir
+VERSION are installed."
+ (string-append path "/lib/elixir/" version))
+
+(define* (strip-prefix name #:optional (prefix "elixir-"))
+ "Return NAME without the prefix PREFIX."
+ (if (string-prefix? prefix name)
+ (string-drop name (string-length prefix))
+ name))
+
+(define (mix-build-dir mix-build-root mix-env)
+ "Return the directory where build artifacts are to be installed according to
+en environment MIX-ENV in the current directory. MIX-BUILD-ROOT depends on the
+package arguments. See: https://hexdocs.pm/mix/1.15/Mix.html#module-environment-variables"
+ (string-append mix-build-root "/" mix-env "/lib"))
+
+(define (elixir-version inputs)
+ "Return an X.Y string where X and Y are respectively the major and minor version number of PACKAGE.
+Example: /gnu/store/…-elixir-1.14.0 → 1.14"
+ ((compose
+ (cute string-join <> ".")
+ (cute take <> 2)
+ (cute string-split <> #\.)
+ strip-prefix
+ strip-store-file-name)
+ (assoc-ref inputs "elixir")))
+
+(define* (unpack #:key source mix-path #:allow-other-keys)
+ "Unpack SOURCE in the working directory, and change directory within the
+source. When SOURCE is a directory, copy it in a sub-directory of the current
+working directory."
+ (let ((gnu-unpack (assoc-ref gnu:%standard-phases 'unpack)))
+ (gnu-unpack #:source source)
+ (when (file-exists? "contents.tar.gz")
+ (invoke "tar" "xvf" "contents.tar.gz"))))
+
+(define (list-directories dir)
+ "List absolute paths of directories directly under the directory DIR."
+ (map (cute string-append dir "/" <>)
+ (scandir dir (lambda (filename)
+ (and (not (member filename '("." "..")))
+ (directory-exists? (string-append dir "/" filename)))))))
+
+(define* (set-mix-env #:key inputs mix-path mix-exs #:allow-other-keys)
+ "Set environment variables.
+See: https://hexdocs.pm/mix/1.15.7/Mix.html#module-environment-variables"
+ (setenv "MIX_ARCHIVES" "archives")
+ (setenv "MIX_BUILD_ROOT" "_build")
+ (setenv "MIX_DEPS_PATH" "deps")
+ (setenv "MIX_EXS" mix-exs)
+ (setenv "MIX_HOME" (getcwd))
+ (setenv "MIX_PATH" (or mix-path ""))
+ (setenv "MIX_REBAR3" (string-append (assoc-ref inputs "rebar3") "/bin/rebar3")))
+
+(define* (set-elixir-version #:key inputs #:allow-other-keys)
+ "Store the version number of the Elixir input in a parameter."
+ (%elixir-version (elixir-version inputs))
+ (format #t "Elixir version: ~a~%" (%elixir-version)))
+
+(define* (build #:key mix-environments #:allow-other-keys)
+ "Builds the Mix project."
+ (for-each (lambda (mix-env)
+ (setenv "MIX_ENV" mix-env)
+ (invoke "mix" "compile" "--no-deps-check"))
+ mix-environments))
+
+(define* (check #:key (tests? #t) #:allow-other-keys)
+ "Test the Mix project."
+ (if tests?
+ (invoke "mix" "test" "--no-deps-check")
+ (format #t "tests? = ~a~%" tests?)))
+
+(define* (remove-mix-dirs . _)
+ "Remove all .mix/ directories.
+We do not want to copy them to the installation directory."
+ (for-each delete-file-recursively
+ (find-files "." (file-name-predicate "\\.mix$") #:directories? #t)))
+
+(define (package-name->elixir-name name+ver)
+ "Convert the Guix package NAME-VER to the corresponding Elixir name-version
+format. Example: elixir-a-pkg-1.2.3 -> a_pkg"
+ ((compose
+ (cute string-join <> "_")
+ (cute drop-right <> 1)
+ (cute string-split <> #\-))
+ (strip-prefix name+ver)))
+
+(define* (install #:key
+ inputs
+ outputs
+ name
+ build-per-environment
+ #:allow-other-keys)
+ "Install build artifacts in the store."
+ (let* ((lib-name (package-name->elixir-name name))
+ (lib-dir (string-append (elixir-libdir (assoc-ref outputs "out")) "/" lib-name))
+ (root (getenv "MIX_BUILD_ROOT"))
+ (env (if build-per-environment "prod" "shared")))
+ (mkdir-p lib-dir)
+ (copy-recursively (string-append (mix-build-dir root env) "/" lib-name) lib-dir
+ #:follow-symlinks? #t)))
+
+(define %standard-phases
+ (modify-phases gnu:%standard-phases
+ (delete 'bootstrap)
+ (delete 'configure)
+ (add-after 'install-locale 'set-mix-env set-mix-env)
+ (add-after 'set-mix-env 'set-elixir-version set-elixir-version)
+ (replace 'unpack unpack)
+ (replace 'build build)
+ (replace 'check check)
+ (add-before 'install 'remove-mix-dirs remove-mix-dirs)
+ (replace 'install install)))
+
+(define* (mix-build #:key inputs (phases %standard-phases)
+ #:allow-other-keys #:rest args)
+ "Build the given Mix package, applying all of PHASES in order."
+ (apply gnu:gnu-build #:inputs inputs #:phases phases args))
+
+;;; mix-build-system.scm ends here
diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm
index b845b8aab9..b2871c3c10 100644
--- a/guix/build/syscalls.scm
+++ b/guix/build/syscalls.scm
@@ -192,6 +192,7 @@
terminal-window-size
terminal-columns
terminal-rows
+ terminal-string-width
openpty
login-tty
@@ -1097,6 +1098,7 @@ Turning finalization off shuts down the finalization thread as a side effect."
("armv7l" 120)
("aarch64" 220)
("ppc64le" 120)
+ ("riscv64" 220)
(_ #f))))
(lambda (flags)
"Create a new child process by duplicating the current parent process.
@@ -2336,6 +2338,26 @@ PORT, trying to guess a reasonable value if all else fails. The result is
always a positive integer."
(terminal-dimension window-size-rows port (const 25)))
+(define terminal-string-width
+ (let ((mbstowcs (and=> (false-if-exception
+ (dynamic-func "mbstowcs" (dynamic-link)))
+ (cute pointer->procedure int <> (list '* '* size_t))))
+ (wcswidth (and=> (false-if-exception
+ (dynamic-func "wcswidth" (dynamic-link)))
+ (cute pointer->procedure int <> (list '* size_t)))))
+ (if (and mbstowcs wcswidth)
+ (lambda (str)
+ "Return the width of a string as it would be printed on the terminal.
+This procedure accounts for characters that have a different width than 1, such
+as CJK double-width characters."
+ (let ((wchar (make-bytevector (* (+ (string-length str) 1) 4))))
+ (mbstowcs (bytevector->pointer wchar)
+ (string->pointer str)
+ (string-length str))
+ (wcswidth (bytevector->pointer wchar)
+ (string-length str))))
+ string-length))) ;using a statically-linked Guile
+
(define openpty
(let ((proc (syscall->procedure int "openpty" '(* * * * *)
#:library "libutil")))
diff --git a/guix/build/vim-build-system.scm b/guix/build/vim-build-system.scm
new file mode 100644
index 0000000000..e11965cc27
--- /dev/null
+++ b/guix/build/vim-build-system.scm
@@ -0,0 +1,119 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2022 Jonathan Scoresby <me@jonscoresby.com>
+;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il>
+;;;
+;;; 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 build vim-build-system)
+ #:use-module ((guix build copy-build-system)
+ #:prefix copy:)
+ #:use-module (guix build utils)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 ftw)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-26)
+ #:export (%standard-phases vim-build))
+
+;; Commentary:
+;;
+;; System for installing vim and neovim plugins. It downloads
+;; the source and copies the appropriate files to vim and nvim
+;; packpaths. It then generates helptags.
+;;
+;; Code:
+
+(define copy:install
+ (assoc-ref copy:%standard-phases 'install))
+
+(define vim-path
+ "/share/vim/vimfiles/pack/guix/")
+(define nvim-path
+ "/share/nvim/site/pack/guix/")
+
+(define* (install #:key plugin-name
+ install-plan
+ neovim?
+ vim?
+ mode
+ outputs
+ #:allow-other-keys)
+
+ (let* ((include-regexp '(".*\\/.*\\/.*"))
+ (exclude-regexp '("^scripts/.*"
+ "tests?/.*" "^t/.*"
+ "assets/.*"
+ ".*\\/\\..*"))
+ (vim-install
+ (if vim?
+ `(("." ,(string-append vim-path mode "/" plugin-name "/")
+ #:include-regexp ,include-regexp
+ #:exclude-regexp ,exclude-regexp))
+ '()))
+ (neovim-install
+ (if neovim?
+ `(("." ,(string-append nvim-path mode "/" plugin-name "/")
+ #:include-regexp ,include-regexp
+ #:exclude-regexp ,exclude-regexp))
+ '())))
+ (copy:install #:outputs outputs
+ #:install-plan (append vim-install
+ neovim-install
+ install-plan))))
+
+(define* (generate-helptags #:key plugin-name
+ neovim?
+ vim?
+ mode
+ outputs
+ #:allow-other-keys)
+
+ (define (vim-generate-helptags output)
+ (invoke "vim" "--clean" "-en" "--cmd"
+ (string-append "helptags "
+ output vim-path mode "/" plugin-name "/doc")
+ "--cmd" "q"))
+
+ (define (neovim-generate-helptags output)
+ (invoke "nvim" "--clean" "--headless" "-en" "--cmd"
+ (string-append "helptags "
+ output nvim-path mode "/" plugin-name "/doc")
+ "--cmd" "q"))
+
+ (when (scandir "./doc")
+ (let ((out (assoc-ref outputs "out")))
+ (when vim?
+ (vim-generate-helptags out))
+ (when neovim?
+ (neovim-generate-helptags out)))))
+
+(define %standard-phases
+ ;; Everything is as with the Copy Build System except for
+ ;; the addition of the generate-helptags phase and a few
+ ;; custom actions are added to the install phase
+ (modify-phases copy:%standard-phases
+ (replace 'install install)
+ (add-after 'install 'generate-helptags generate-helptags)))
+
+(define* (vim-build #:key inputs
+ (phases %standard-phases)
+ #:allow-other-keys #:rest args)
+ "Build the given package, applying all of PHASES in order."
+ (apply copy:copy-build
+ #:inputs inputs
+ #:phases phases
+ args))
+
+;;; vim-build-system.scm ends here
diff --git a/guix/build/zig-build-system.scm b/guix/build/zig-build-system.scm
index d414ebfb17..8352a73324 100644
--- a/guix/build/zig-build-system.scm
+++ b/guix/build/zig-build-system.scm
@@ -47,6 +47,7 @@
zig-build-flags
zig-release-type ;; "safe", "fast" or "small" empty for a
;; debug build"
+ target
#:allow-other-keys)
"Build a given Zig package."
@@ -56,6 +57,9 @@
"--prefix-lib-dir" "lib"
"--prefix-exe-dir" "bin"
"--prefix-include-dir" "include"
+ ,@(if target
+ (list (string-append "-Dtarget=" target))
+ '())
,@(if zig-release-type
(list (string-append "-Drelease-" zig-release-type))
'())
@@ -65,9 +69,10 @@
(define* (check #:key tests?
zig-test-flags
+ target
#:allow-other-keys)
"Run all the tests"
- (when tests?
+ (when (and tests? (not target))
(let ((old-destdir (getenv "DESTDIR")))
(setenv "DESTDIR" "test-out") ;; Avoid colisions with the build output
(let ((call `("zig" "build" "test"
diff --git a/guix/deprecation.scm b/guix/deprecation.scm
index 8147a01e24..47e653dfb2 100644
--- a/guix/deprecation.scm
+++ b/guix/deprecation.scm
@@ -103,7 +103,7 @@ This will write a deprecation warning to GUIX-WARNING-PORT."
#'(define-deprecated variable alias alias)))))
(define-syntax-rule (define-deprecated/public body ...)
- "Like 'define/deprecated', but export all the newly introduced bindings."
+ "Like 'define-deprecated', but export all the newly introduced bindings."
(define-deprecated public body ...))
(define-syntax-rule (define-deprecated/alias deprecated replacement)
diff --git a/guix/docker.scm b/guix/docker.scm
index 5e6460f43f..1c6f59568f 100644
--- a/guix/docker.scm
+++ b/guix/docker.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2017, 2018, 2019, 2021 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2018 Chris Marusich <cmmarusich@gmail.com>
;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
+;;; Copyright © 2023 Oleg Pykhalov <go.wigust@gmail.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -29,16 +30,27 @@
with-directory-excursion
invoke))
#:use-module (gnu build install)
+ #:use-module ((guix build store-copy)
+ #:select (file-size))
#:use-module (json) ;guile-json
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-19)
#:use-module (srfi srfi-26)
+ #:use-module (srfi srfi-71)
#:use-module ((texinfo string-utils)
#:select (escape-special-chars))
#:use-module (rnrs bytevectors)
#:use-module (ice-9 ftw)
#:use-module (ice-9 match)
- #:export (build-docker-image))
+ #:export (%docker-image-max-layers
+ build-docker-image))
+
+;; The maximum number of layers allowed in a Docker image is typically around
+;; 128, although it may vary depending on the Docker daemon. However, we
+;; recommend setting the limit to 100 to ensure sufficient room for future
+;; extensions.
+(define %docker-image-max-layers
+ #f)
;; Generate a 256-bit identifier in hexadecimal encoding for the Docker image.
(define docker-id
@@ -92,12 +104,12 @@ Return a version of TAG that follows these rules."
(make-string (- min-length l) padding-character)))
(_ normalized-name))))
-(define* (manifest path id #:optional (tag "guix"))
+(define* (manifest path layers #:optional (tag "guix"))
"Generate a simple image manifest."
(let ((tag (canonicalize-repository-name tag)))
`#(((Config . "config.json")
(RepoTags . #(,(string-append tag ":latest")))
- (Layers . #(,(string-append id "/layer.tar")))))))
+ (Layers . ,(list->vector layers))))))
;; According to the specifications this is required for backwards
;; compatibility. It duplicates information provided by the manifest.
@@ -106,8 +118,8 @@ Return a version of TAG that follows these rules."
`((,(canonicalize-repository-name tag) . ((latest . ,id)))))
;; See https://github.com/opencontainers/image-spec/blob/master/config.md
-(define* (config layer time arch #:key entry-point (environment '()))
- "Generate a minimal image configuration for the given LAYER file."
+(define* (config layers-diff-ids time arch #:key entry-point (environment '()))
+ "Generate a minimal image configuration for the given LAYERS files."
;; "architecture" must be values matching "platform.arch" in the
;; runtime-spec at
;; https://github.com/opencontainers/runtime-spec/blob/v1.0.0-rc2/config.md#platform
@@ -125,7 +137,7 @@ Return a version of TAG that follows these rules."
(container_config . #nil)
(os . "linux")
(rootfs . ((type . "layers")
- (diff_ids . #(,(layer-diff-id layer)))))))
+ (diff_ids . ,(list->vector layers-diff-ids))))))
(define directive-file
;; Return the file or directory created by a 'evaluate-populate-directive'
@@ -136,6 +148,26 @@ Return a version of TAG that follows these rules."
(('directory name _ ...)
(string-trim name #\/))))
+(define (size-sorted-store-items items max-layers)
+ "Split list of ITEMS at %MAX-LAYERS and sort by disk usage."
+ (let* ((items-length (length items))
+ (head tail
+ (split-at
+ (map (match-lambda ((size . item) item))
+ (sort (map (lambda (item)
+ (cons (file-size item) item))
+ items)
+ (lambda (item1 item2)
+ (< (match item2 ((size . _) size))
+ (match item1 ((size . _) size))))))
+ (if (>= items-length max-layers)
+ (- max-layers 2)
+ (1- items-length)))))
+ (list head tail)))
+
+(define (create-empty-tar file)
+ (invoke "tar" "-cf" file "--files-from" "/dev/null"))
+
(define* (build-docker-image image paths prefix
#:key
(repository "guix")
@@ -146,11 +178,13 @@ Return a version of TAG that follows these rules."
entry-point
(environment '())
compressor
- (creation-time (current-time time-utc)))
- "Write to IMAGE a Docker image archive containing the given PATHS. PREFIX
-must be a store path that is a prefix of any store paths in PATHS. REPOSITORY
-is a descriptive name that will show up in \"REPOSITORY\" column of the output
-of \"docker images\".
+ (creation-time (current-time time-utc))
+ max-layers
+ root-system)
+ "Write to IMAGE a layerer Docker image archive containing the given PATHS.
+PREFIX must be a store path that is a prefix of any store paths in PATHS.
+REPOSITORY is a descriptive name that will show up in \"REPOSITORY\" column of
+the output of \"docker images\".
When DATABASE is true, copy it to /var/guix/db in the image and create
/var/guix/gcroots and friends.
@@ -172,7 +206,14 @@ non-empty directory, then its contents will be recursively added, as well.
SYSTEM is a GNU triplet (or prefix thereof) of the system the binaries in
PATHS are for; it is used to produce metadata in the image. Use COMPRESSOR, a
command such as '(\"gzip\" \"-9n\"), to compress IMAGE. Use CREATION-TIME, a
-SRFI-19 time-utc object, as the creation time in metadata."
+SRFI-19 time-utc object, as the creation time in metadata.
+
+When MAX-LAYERS is not false build layered image, providing a Docker
+image with store paths splitted in their own layers to improve sharing
+between images.
+
+ROOT-SYSTEM is a directory with a provisioned root file system, which will be
+added to image as a layer."
(define (sanitize path-fragment)
(escape-special-chars
;; GNU tar strips the leading slash off of absolute paths before applying
@@ -203,6 +244,59 @@ SRFI-19 time-utc object, as the creation time in metadata."
(if (eq? '() transformations)
'()
`("--transform" ,(transformations->expression transformations))))
+ (define (seal-layer)
+ ;; Add 'layer.tar' to 'image.tar' under the right name. Return its hash.
+ (let* ((file-hash (layer-diff-id "layer.tar"))
+ (file-name (string-append file-hash "/layer.tar")))
+ (mkdir file-hash)
+ (rename-file "layer.tar" file-name)
+ (invoke "tar" "-rf" "image.tar" file-name)
+ (delete-file file-name)
+ file-hash))
+ (define layers-hashes
+ ;; Generate a tarball that includes container image layers as tarballs,
+ ;; along with a manifest.json file describing the layer and config file
+ ;; locations.
+ (match-lambda
+ (((head ...) (tail ...) id)
+ (create-empty-tar "image.tar")
+ (let* ((head-layers
+ (map
+ (lambda (file)
+ (invoke "tar" "cf" "layer.tar" file)
+ (seal-layer))
+ head))
+ (tail-layer
+ (begin
+ (create-empty-tar "layer.tar")
+ (for-each (lambda (file)
+ (invoke "tar" "-rf" "layer.tar" file))
+ tail)
+ (let* ((file-hash (layer-diff-id "layer.tar"))
+ (file-name (string-append file-hash "/layer.tar")))
+ (mkdir file-hash)
+ (rename-file "layer.tar" file-name)
+ (invoke "tar" "-rf" "image.tar" file-name)
+ (delete-file file-name)
+ file-hash)))
+ (customization-layer
+ (let* ((file-id (string-append id "/layer.tar"))
+ (file-hash (layer-diff-id file-id))
+ (file-name (string-append file-hash "/layer.tar")))
+ (mkdir file-hash)
+ (rename-file file-id file-name)
+ (invoke "tar" "-rf" "image.tar" file-name)
+ file-hash))
+ (all-layers
+ (append head-layers (list tail-layer customization-layer))))
+ (with-output-to-file "manifest.json"
+ (lambda ()
+ (scm->json (manifest prefix
+ (map (cut string-append <> "/layer.tar")
+ all-layers)
+ repository))))
+ (invoke "tar" "-rf" "image.tar" "manifest.json")
+ all-layers))))
(let* ((directory "/tmp/docker-image") ;temporary working directory
(id (docker-id prefix))
(time (date->string (time-utc->date creation-time) "~4"))
@@ -229,26 +323,39 @@ SRFI-19 time-utc object, as the creation time in metadata."
(with-output-to-file "json"
(lambda () (scm->json (image-description id time))))
- ;; Create a directory for the non-store files that need to go into the
- ;; archive.
- (mkdir "extra")
+ (if root-system
+ (let ((directory (getcwd)))
+ (with-directory-excursion root-system
+ (apply invoke "tar"
+ "-cf" (string-append directory "/layer.tar")
+ `(,@transformation-options
+ ,@(tar-base-options)
+ ,@(scandir "."
+ (lambda (file)
+ (not (member file '("." "..")))))))))
+ (begin
+ ;; Create a directory for the non-store files that need to go
+ ;; into the archive.
+ (mkdir "extra")
- (with-directory-excursion "extra"
- ;; Create non-store files.
- (for-each (cut evaluate-populate-directive <> "./")
- extra-files)
+ (with-directory-excursion "extra"
+ ;; Create non-store files.
+ (for-each (cut evaluate-populate-directive <> "./")
+ extra-files)
- (when database
- ;; Initialize /var/guix, assuming PREFIX points to a profile.
- (install-database-and-gc-roots "." database prefix))
+ (when database
+ ;; Initialize /var/guix, assuming PREFIX points to a
+ ;; profile.
+ (install-database-and-gc-roots "." database prefix))
- (apply invoke "tar" "-cf" "../layer.tar"
- `(,@transformation-options
- ,@(tar-base-options)
- ,@paths
- ,@(scandir "."
- (lambda (file)
- (not (member file '("." ".."))))))))
+ (apply invoke "tar" "-cf" "../layer.tar"
+ `(,@transformation-options
+ ,@(tar-base-options)
+ ,@(if max-layers '() paths)
+ ,@(scandir "."
+ (lambda (file)
+ (not (member file '("." ".."))))))))
+ (delete-file-recursively "extra")))
;; It is possible for "/" to show up in the archive, especially when
;; applying transformations. For example, the transformation
@@ -261,24 +368,37 @@ SRFI-19 time-utc object, as the creation time in metadata."
;; error messages.
(with-error-to-port (%make-void-port "w")
(lambda ()
- (system* "tar" "--delete" "/" "-f" "layer.tar")))
-
- (delete-file-recursively "extra"))
+ (system* "tar" "--delete" "/" "-f" "layer.tar"))))
(with-output-to-file "config.json"
(lambda ()
- (scm->json (config (string-append id "/layer.tar")
- time arch
- #:environment environment
- #:entry-point entry-point))))
- (with-output-to-file "manifest.json"
- (lambda ()
- (scm->json (manifest prefix id repository))))
- (with-output-to-file "repositories"
- (lambda ()
- (scm->json (repositories prefix id repository)))))
-
- (apply invoke "tar" "-cf" image "-C" directory
- `(,@(tar-base-options #:compressor compressor)
- "."))
+ (scm->json
+ (config (if max-layers
+ (layers-hashes
+ (append (size-sorted-store-items paths max-layers)
+ (list id)))
+ (list (layer-diff-id (string-append id "/layer.tar"))))
+ time arch
+ #:environment environment
+ #:entry-point entry-point))))
+ (if max-layers
+ (begin
+ (invoke "tar" "-rf" "image.tar" "config.json")
+ (if compressor
+ (begin
+ (apply invoke `(,@compressor "image.tar"))
+ (copy-file "image.tar.gz" image))
+ (copy-file "image.tar" image)))
+ (begin
+ (with-output-to-file "manifest.json"
+ (lambda ()
+ (scm->json (manifest prefix
+ (list (string-append id "/layer.tar"))
+ repository))))
+ (with-output-to-file "repositories"
+ (lambda ()
+ (scm->json (repositories prefix id repository))))
+ (apply invoke "tar" "-cf" image
+ `(,@(tar-base-options #:compressor compressor)
+ ".")))))
(delete-file-recursively directory)))
diff --git a/guix/download.scm b/guix/download.scm
index 31a41e8183..21d02ab203 100644
--- a/guix/download.scm
+++ b/guix/download.scm
@@ -117,11 +117,9 @@
"http://internode.dl.sourceforge.net/project/"
"http://jaist.dl.sourceforge.net/project/"
"http://liquidtelecom.dl.sourceforge.net/project/"
- ;; "http://nbtelecom.dl.sourceforge.net/project/" ;never returns 404s
"http://nchc.dl.sourceforge.net/project/"
"http://netcologne.dl.sourceforge.net/project/"
"http://netix.dl.sourceforge.net/project/"
- "http://pilotfiber.dl.sourceforge.net/project/"
"http://tenet.dl.sourceforge.net/project/")
(netfilter.org ; https://www.netfilter.org/mirrors.html
"http://ftp.netfilter.org/pub/"
@@ -129,23 +127,25 @@
"ftp://ftp.hu.netfilter.org/"
"ftp://www.lt.netfilter.org/pub/")
(kernel.org
- "http://linux-kernel.uio.no/pub/"
+ "https://cdn.kernel.org/pub/"
"http://ftp.be.debian.org/pub/"
"https://mirrors.edge.kernel.org/pub/"
"ftp://ftp.funet.fi/pub/mirrors/ftp.kernel.org/pub/")
- (apache ; from http://www.apache.org/mirrors/dist.html
- "http://www.eu.apache.org/dist/"
- "http://www.us.apache.org/dist/"
- "https://ftp.nluug.nl/internet/apache/"
+ (apache
+ "https://dlcdn.apache.org/"
+ "https://downloads.apache.org/"
+ "https://mirrors.sonic.net/apache/"
+ "https://apache.osuosl.org/"
+ "https://mirrors.ircam.fr/pub/apache/"
+ "https://apache-mirror.rbc.ru/pub/apache/"
+ "https://mirrors.ibiblio.org/apache/"
+
+ ;; No HTTPS.
"http://apache.mirror.iweb.ca/"
- "http://mirrors.ircam.fr/pub/apache/"
"http://apache.mirrors.ovh.net/ftp.apache.org/dist/"
- "http://apache-mirror.rbc.ru/pub/apache/"
- "ftp://ftp.osuosl.org/pub/apache/"
- "http://mirrors.ibiblio.org/apache/"
;; As a last resort, try the archive.
- "http://archive.apache.org/dist/")
+ "https://archive.apache.org/dist/")
(xorg ; from http://www.x.org/wiki/Releases/Download
"http://www.x.org/releases/" ; main mirrors
"http://mirror.csclub.uwaterloo.ca/x.org/" ; North America
@@ -271,7 +271,6 @@
"https://mirror.kumi.systems/kde/ftp/"
"https://mirrors.ircam.fr/pub/KDE/"
"https://ftp.gwdg.de/pub/linux/kde/"
- "https://mirrors.gethosted.online/kde/pub/kde/"
"https://fr2.rpmfind.net/linux/KDE/"
"https://mirror.faigner.de/kde/ftp/"
"https://www.mirrorservice.org/sites/download.kde.org/"
@@ -288,7 +287,6 @@
"https://mirrors.nav.ro/kde/"
"https://mirrors.xtom.ee/kde/"
"https://ftp.funet.fi/pub/mirrors/ftp.kde.org/pub/kde/"
- "https://kde.ip-connect.vn.ua/"
"https://mirrors.netix.net/kde/"
"https://ftp.cc.uoc.gr/mirrors/kde/"
;; North America
@@ -307,7 +305,7 @@
"https://mirrors.xtom.jp/kde/"
"https://mirrors.xtom.hk/kde/"
;; Africa
- "http://mirror.retentionrange.co.bw/kde/"
+ "https://mirror.dimensiondata.com/mirror/ftp.kde.org/"
;; Oceania
"https://mirrors.xtom.au/kde/")
(openbsd
diff --git a/guix/gexp.scm b/guix/gexp.scm
index 0fe4f1c98a..29819878fa 100644
--- a/guix/gexp.scm
+++ b/guix/gexp.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2014-2022 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2014-2023 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2018 Clément Lassieur <clement@lassieur.org>
;;; Copyright © 2018 Jan Nieuwenhuizen <janneke@gnu.org>
;;; Copyright © 2019, 2020 Mathieu Othacehe <m.othacehe@gmail.com>
@@ -775,6 +775,23 @@ x86_64-linux when COREUTILS is lowered."
whether this should be considered a \"native\" input or not."
(%gexp-input thing output native?))
+;; Allow <gexp-input>s to be used within gexps. This is useful when willing
+;; to force a specific reference to an object, as in (gexp-input hwloc "bin"),
+;; which forces a reference to the "bin" output of 'hwloc' instead of leaving
+;; it up to the recipient to pick the right output.
+(define-gexp-compiler gexp-input-compiler <gexp-input>
+ compiler => (lambda (obj system target)
+ (match obj
+ (($ <gexp-input> thing output native?)
+ (lower-object thing system
+ #:target (and (not native?) target)))))
+ expander => (lambda (obj lowered output/ignored)
+ (match obj
+ (($ <gexp-input> thing output native?)
+ (let ((expand (or (lookup-expander thing)
+ (lookup-expander lowered))))
+ (expand thing lowered output))))))
+
;; Reference to one of the derivation's outputs, for gexps used in
;; derivations.
(define-record-type <gexp-output>
@@ -917,6 +934,11 @@ When TARGET is true, use it as the cross-compilation target triplet."
corresponding <derivation-input> or store item."
(define tuple->gexp-input
(match-lambda
+ (((? gexp-input? input))
+ ;; This case lets users specify the output of interest more
+ ;; conveniently, for instance by passing (gexp-input hwloc "lib") to
+ ;; the 'references-file' procedure.
+ input)
((thing)
(%gexp-input thing "out" (not target)))
((thing output)
@@ -1135,10 +1157,9 @@ applicable.
When REFERENCES-GRAPHS is true, it must be a list of tuples of one of the
following forms:
- (FILE-NAME PACKAGE)
- (FILE-NAME PACKAGE OUTPUT)
- (FILE-NAME DERIVATION)
- (FILE-NAME DERIVATION OUTPUT)
+ (FILE-NAME OBJ)
+ (FILE-NAME OBJ OUTPUT)
+ (FILE-NAME GEXP-INPUT)
(FILE-NAME STORE-ITEM)
The right-hand-side of each element of REFERENCES-GRAPHS is automatically made
diff --git a/guix/git-download.scm b/guix/git-download.scm
index 5d5d73dc6b..3de6ae970d 100644
--- a/guix/git-download.scm
+++ b/guix/git-download.scm
@@ -4,6 +4,7 @@
;;; Copyright © 2017 Christopher Baines <mail@cbaines.net>
;;; Copyright © 2020 Jakub Kądziołka <kuba@kadziolka.net>
;;; Copyright © 2023 Simon Tournier <zimon.toutoune@gmail.com>
+;;; Copyright © 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -54,6 +55,7 @@
git-reference-recursive?
git-fetch
+ git-fetch/lfs
git-version
git-file-name
git-predicate))
@@ -79,30 +81,36 @@
(let ((distro (resolve-interface '(gnu packages version-control))))
(module-ref distro 'git-minimal)))
-(define* (git-fetch/in-band ref hash-algo hash
- #:optional name
- #:key (system (%current-system))
- (guile (default-guile))
- (git (git-package)))
- "Return a fixed-output derivation that performs a Git checkout of REF, using
-GIT and GUILE (thus, said derivation depends on GIT and GUILE).
+(define (git-lfs-package)
+ "Return the default 'git-lfs' package."
+ (let ((distro (resolve-interface '(gnu packages version-control))))
+ (module-ref distro 'git-lfs)))
-This method is deprecated in favor of the \"builtin:git-download\" builder.
-It will be removed when versions of guix-daemon implementing
-\"builtin:git-download\" will be sufficiently widespread."
+(define* (git-fetch/in-band* ref hash-algo hash
+ #:optional name
+ #:key (system (%current-system))
+ (guile (default-guile))
+ (git (git-package))
+ git-lfs)
+ "Shared implementation code for git-fetch/in-band & friends. Refer to their
+respective documentation."
(define inputs
- `(("git" ,(or git (git-package)))
-
- ;; When doing 'git clone --recursive', we need sed, grep, etc. to be
- ;; available so that 'git submodule' works.
+ `(,(or git (git-package))
+ ,@(if git-lfs
+ (list git-lfs)
+ '())
,@(if (git-reference-recursive? ref)
- (standard-packages)
+ ;; TODO: remove (standard-packages) after
+ ;; 48e528a26f9c019eeaccf5e3de3126aa02c98d3b is merged into master;
+ ;; currently when doing 'git clone --recursive', we need sed, grep,
+ ;; etc. to be available so that 'git submodule' works.
+ (map second (standard-packages))
;; The 'swh-download' procedure requires tar and gzip.
- `(("gzip" ,(module-ref (resolve-interface '(gnu packages compression))
- 'gzip))
- ("tar" ,(module-ref (resolve-interface '(gnu packages base))
- 'tar))))))
+ (list (module-ref (resolve-interface '(gnu packages compression))
+ 'gzip)
+ (module-ref (resolve-interface '(gnu packages base))
+ 'tar)))))
(define guile-json
(module-ref (resolve-interface '(gnu packages guile)) 'guile-json-4))
@@ -126,7 +134,7 @@ It will be removed when versions of guix-daemon implementing
(define build
(with-imported-modules modules
- (with-extensions (list guile-json gnutls ;for (guix swh)
+ (with-extensions (list guile-json gnutls ;for (guix swh)
guile-lzlib)
#~(begin
(use-modules (guix build git)
@@ -134,6 +142,9 @@ It will be removed when versions of guix-daemon implementing
#:select (set-path-environment-variable))
(ice-9 match))
+ (define lfs?
+ (call-with-input-string (getenv "git lfs?") read))
+
(define recursive?
(call-with-input-string (getenv "git recursive?") read))
@@ -144,18 +155,17 @@ It will be removed when versions of guix-daemon implementing
#+(file-append glibc-locales "/lib/locale"))
(setlocale LC_ALL "en_US.utf8")
- ;; The 'git submodule' commands expects Coreutils, sed,
- ;; grep, etc. to be in $PATH.
- (set-path-environment-variable "PATH" '("bin")
- (match '#+inputs
- (((names dirs outputs ...) ...)
- dirs)))
+ ;; The 'git submodule' commands expects Coreutils, sed, grep,
+ ;; etc. to be in $PATH. This also ensures that git extensions are
+ ;; found.
+ (set-path-environment-variable "PATH" '("bin") '#+inputs)
(setvbuf (current-output-port) 'line)
(setvbuf (current-error-port) 'line)
(git-fetch-with-fallback (getenv "git url") (getenv "git commit")
#$output
+ #:lfs? lfs?
#:recursive? recursive?
#:git-command "git")))))
@@ -175,18 +185,49 @@ It will be removed when versions of guix-daemon implementing
(git-reference-url ref))))
("git commit" . ,(git-reference-commit ref))
("git recursive?" . ,(object->string
- (git-reference-recursive? ref))))
+ (git-reference-recursive? ref)))
+ ("git lfs?" . ,(if git-lfs "#t" "#f")))
#:leaked-env-vars '("http_proxy" "https_proxy"
"LC_ALL" "LC_MESSAGES" "LANG"
"COLUMNS")
#:system system
- #:local-build? #t ;don't offload repo cloning
+ #:local-build? #t ;don't offload repo cloning
#:hash-algo hash-algo
#:hash hash
#:recursive? #t
#:guile-for-build guile)))
+(define* (git-fetch/in-band ref hash-algo hash
+ #:optional name
+ #:key (system (%current-system))
+ (guile (default-guile))
+ (git (git-package)))
+ "Return a fixed-output derivation that performs a Git checkout of REF, using
+GIT and GUILE (thus, said derivation depends on GIT and GUILE).
+
+This method is deprecated in favor of the \"builtin:git-download\" builder.
+It will be removed when versions of guix-daemon implementing
+\"builtin:git-download\" will be sufficiently widespread."
+ (git-fetch/in-band* ref hash-algo hash name
+ #:system system
+ #:guile guile
+ #:git git))
+
+(define* (git-fetch/lfs ref hash-algo hash
+ #:optional name
+ #:key (system (%current-system))
+ (guile (default-guile))
+ (git (git-package))
+ (git-lfs (git-lfs-package)))
+ "Like git-fetch/in-band, but with support for the Git Large File
+Storage (LFS) extension."
+ (git-fetch/in-band* ref hash-algo hash name
+ #:system system
+ #:guile guile
+ #:git git
+ #:git-lfs git-lfs))
+
(define* (git-fetch/built-in ref hash-algo hash
#:optional name
#:key (system (%current-system)))
diff --git a/guix/git.scm b/guix/git.scm
index b7182305cf..cbcdb1904b 100644
--- a/guix/git.scm
+++ b/guix/git.scm
@@ -1,6 +1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2017, 2020 Mathieu Othacehe <m.othacehe@gmail.com>
-;;; Copyright © 2018-2022 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2018-2023 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>
@@ -29,15 +29,18 @@
#:use-module (guix cache)
#:use-module (gcrypt hash)
#:use-module ((guix build utils)
- #:select (mkdir-p delete-file-recursively))
+ #:select (mkdir-p delete-file-recursively invoke/quiet))
#:use-module (guix store)
#:use-module (guix utils)
#:use-module (guix records)
+ #:use-module ((guix build syscalls)
+ #:select (terminal-string-width))
#:use-module (guix gexp)
#:autoload (guix git-download)
(git-reference-url git-reference-commit git-reference-recursive?)
+ #:autoload (guix config) (%git)
#:use-module (guix sets)
- #:use-module ((guix diagnostics) #:select (leave warning))
+ #:use-module ((guix diagnostics) #:select (leave warning info))
#:use-module (guix progress)
#:autoload (guix swh) (swh-download commit-id?)
#:use-module (rnrs bytevectors)
@@ -154,7 +157,7 @@ the 'SSL_CERT_FILE' and 'SSL_CERT_DIR' environment variables."
;; TODO: Both should be handled & exposed by the PROGRESS-BAR API instead.
(define width
(max (- (current-terminal-columns)
- (string-length label) 7)
+ (terminal-string-width label) 7)
3))
(define grain
@@ -428,6 +431,35 @@ could not be fetched from Software Heritage~%")
(rename-file directory trashed)
(delete-file-recursively trashed)))
+(define (packs-in-git-repository directory)
+ "Return the number of pack files under DIRECTORY, a Git checkout."
+ (catch 'system-error
+ (lambda ()
+ (let ((directory (opendir (in-vicinity directory ".git/objects/pack"))))
+ (let loop ((count 0))
+ (match (readdir directory)
+ ((? eof-object?)
+ (closedir directory)
+ count)
+ (str
+ (loop (if (string-suffix? ".pack" str)
+ (+ 1 count)
+ count)))))))
+ (const 0)))
+
+(define (maybe-run-git-gc directory)
+ "Run 'git gc' in DIRECTORY if needed."
+ ;; XXX: As of libgit2 1.3.x (used by Guile-Git), there's no support for GC.
+ ;; Each time a checkout is pulled, a new pack is created, which eventually
+ ;; takes up a lot of space (lots of small, poorly-compressed packs). As a
+ ;; workaround, shell out to 'git gc' when the number of packs in a
+ ;; repository has become "too large", potentially wasting a lot of space.
+ ;; See <https://issues.guix.gnu.org/65720>.
+ (when (> (packs-in-git-repository directory) 25)
+ (info (G_ "compressing cached Git repository at '~a'...~%")
+ directory)
+ (invoke/quiet %git "-C" directory "gc")))
+
(define* (update-cached-checkout url
#:key
(ref '())
@@ -515,6 +547,9 @@ it unchanged."
seconds seconds
nanoseconds nanoseconds))))
+ ;; Run 'git gc' if needed.
+ (maybe-run-git-gc cache-directory)
+
;; When CACHE-DIRECTORY is a sub-directory of the default cache
;; directory, remove expired checkouts that are next to it.
(let ((parent (dirname cache-directory)))
diff --git a/guix/grafts.scm b/guix/grafts.scm
index 48f4c212f7..f4df513daf 100644
--- a/guix/grafts.scm
+++ b/guix/grafts.scm
@@ -22,7 +22,7 @@
#:use-module (guix records)
#:use-module (guix combinators)
#:use-module (guix derivations)
- #:use-module ((guix utils) #:select (%current-system))
+ #:use-module ((guix utils) #:select (%current-system target-hurd?))
#:use-module (guix sets)
#:use-module (guix gexp)
#:use-module (srfi srfi-1)
@@ -98,7 +98,9 @@ OUTPUTS of DRV. This procedure performs \"shallow\" grafting in that GRAFTS
are not recursively applied to dependencies of DRV."
(define glibc-locales
(module-ref (resolve-interface '(gnu packages commencement))
- 'glibc-utf8-locales-final))
+ (if (target-hurd? system)
+ 'glibc-utf8-locales-final/hurd
+ 'glibc-utf8-locales-final)))
(define mapping
;; List of store item pairs.
diff --git a/guix/import/cabal.scm b/guix/import/cabal.scm
index fe03c30254..d32c1c15fe 100644
--- a/guix/import/cabal.scm
+++ b/guix/import/cabal.scm
@@ -130,8 +130,17 @@ to the stack."
(define (context-stack-clear!) ((context-stack) 'clear!))
-;; Indentation of the line being parsed.
-(define current-indentation (make-parameter 0))
+;; Indentation of the line being parsed and that of the previous line.
+(define current-indentation* (make-parameter 0))
+
+(define previous-indentation (make-parameter 0))
+
+(define* (current-indentation #:optional value)
+ (if value
+ (begin
+ (previous-indentation (current-indentation*))
+ (current-indentation* value))
+ (current-indentation*)))
;; Signal to reprocess the beginning of line, in case we need to close more
;; than one indentation level.
@@ -196,27 +205,13 @@ to the stack."
(exprs elif-else) : (append $1 (list ($2 '(()))))
(elif-else) : (list ($1 '(()))))
;; LALR(1) parsers prefer to be left-recursive, which make if-statements slightly involved.
- ;; XXX: This technically allows multiple else statements.
- (elif-else (elif-else ELIF tests OCURLY exprs CCURLY) : (lambda (y) ($1 (list (append (list 'if $3 $5) y))))
- (elif-else ELIF tests open exprs close) : (lambda (y) ($1 (list (append (list 'if $3 $5) y))))
- (elif-else ELSE OCURLY exprs CCURLY) : (lambda (y) ($1 (list $4)))
- ;; The 'open' token after 'tests' is shifted after an 'exprs'
- ;; is found. This is because, instead of 'exprs' a 'OCURLY'
- ;; token is a valid alternative. For this reason, 'open'
- ;; pushes a <parse-context> with a line indentation equal to
- ;; the indentation of 'exprs'.
- ;;
- ;; Differently from this, without the rule above this
- ;; comment, when an 'ELSE' token is found, the 'open' token
- ;; following the 'ELSE' would be shifted immediately, before
- ;; the 'exprs' is found (because there are no other valid
- ;; tokens). The 'open' would therefore create a
- ;; <parse-context> with the indentation of 'ELSE' and not
- ;; 'exprs', creating an inconsistency. We therefore allow
- ;; mixed style conditionals.
- (elif-else ELSE open exprs close) : (lambda (y) ($1 (list $4)))
+ (elif (elif ELIF tests OCURLY exprs CCURLY) : (lambda (y) ($1 (list (append (list 'if $3 $5) y))))
+ (elif ELIF tests open exprs close) : (lambda (y) ($1 (list (append (list 'if $3 $5) y))))
;; Terminating rule.
(if-then) : (lambda (y) (append $1 y)))
+ (elif-else (elif ELSE OCURLY exprs CCURLY) : (lambda (y) ($1 (list $4)))
+ (elif ELSE open exprs close) : (lambda (y) ($1 (list $4)))
+ (elif) : $1)
(if-then (IF tests OCURLY exprs CCURLY) : (list 'if $2 $4)
(IF tests open exprs close) : (list 'if $2 $4))
(tests (TEST OPAREN ID CPAREN) : `(,$1 ,$3)
@@ -237,7 +232,7 @@ to the stack."
(OPAREN tests CPAREN) : $2)
(open () : (context-stack-push!
(make-parse-context (context layout)
- (current-indentation))))
+ (+ 1 (previous-indentation)))))
(close (VCCURLY))))
(define (peek-next-line-indent port)
@@ -655,7 +650,8 @@ If #f use the function 'port-filename' to obtain it."
(let ((cabal-parser (make-cabal-parser)))
(parameterize ((cabal-file-name
(or file-name (port-filename port) "standard input"))
- (current-indentation 0)
+ (current-indentation* 0)
+ (previous-indentation 0)
(check-bol? #f)
(context-stack (make-stack)))
(cabal-parser (make-lexer port) (errorp)))))
@@ -869,7 +865,16 @@ the ordering operation and the version."
(((? string? name) values)
(list name values))
((("import" imports) rest ...)
- (eval (append (append-map (cut assoc-ref common-stanzas <>) imports)
+ (eval (append (append-map
+ ;; The imports are (at least sometimes) a list with one string
+ ;; containing all the names separeted by commas. This splits
+ ;; those strings to a list of strings in the same format that is
+ ;; used in common-stanzas.
+ (cut assoc-ref common-stanzas <>)
+ (append-map (lambda (imports-string)
+ (map (compose string-downcase string-trim-both)
+ (string-split imports-string #\,)))
+ imports))
rest)))
((element rest ...)
(cons (eval element) (eval rest)))
diff --git a/guix/import/composer.scm b/guix/import/composer.scm
new file mode 100644
index 0000000000..1ad608964b
--- /dev/null
+++ b/guix/import/composer.scm
@@ -0,0 +1,268 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 import composer)
+ #:use-module (ice-9 match)
+ #:use-module (json)
+ #:use-module (guix hash)
+ #:use-module (guix base32)
+ #:use-module (guix build git)
+ #:use-module (guix build utils)
+ #:use-module (guix build-system)
+ #:use-module (guix build-system composer)
+ #:use-module (guix import json)
+ #:use-module (guix import utils)
+ #:use-module ((guix licenses) #:prefix license:)
+ #:use-module (guix memoization)
+ #:use-module (guix packages)
+ #:use-module (guix serialization)
+ #:use-module (guix upstream)
+ #:use-module (guix utils)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-11)
+ #:use-module (srfi srfi-26)
+ #:export (composer->guix-package
+ %composer-updater
+ composer-recursive-import
+
+ %composer-base-url))
+
+(define %composer-base-url
+ (make-parameter "https://repo.packagist.org"))
+
+(define (fix-version version)
+ "Return a fixed version from a version string. For instance, v10.1 -> 10.1"
+ (cond
+ ((string-prefix? "version" version)
+ (if (char-set-contains? char-set:digit (string-ref version 7))
+ (substring version 7)
+ (substring version 8)))
+ ((string-prefix? "v" version)
+ (substring version 1))
+ (else version)))
+
+(define (latest-version versions)
+ (fold (lambda (a b) (if (version>? (fix-version a) (fix-version b)) a b))
+ (car versions) versions))
+
+(define (json->require dict)
+ (if dict
+ (let loop ((result '()) (require dict))
+ (match require
+ (() result)
+ ((((? (cut string-contains <> "/") name) . _)
+ require ...)
+ (loop (cons name result) require))
+ ((_ require ...) (loop result require))
+ (_ result)))
+ '()))
+
+(define-json-mapping <composer-source> make-composer-source composer-source?
+ json->composer-source
+ (type composer-source-type)
+ (url composer-source-url)
+ (reference composer-source-reference))
+
+(define-json-mapping <composer-package> make-composer-package composer-package?
+ json->composer-package
+ (description composer-package-description)
+ (homepage composer-package-homepage)
+ (source composer-package-source "source" json->composer-source)
+ (name composer-package-name "name" php-package-name)
+ (version composer-package-version "version" fix-version)
+ (require composer-package-require "require" json->require)
+ (dev-require composer-package-dev-require "require-dev" json->require)
+ (license composer-package-license "license"
+ (lambda (vector)
+ (let ((l (map string->license (vector->list vector))))
+ (if (eq? (length l) 1)
+ (car l)
+ `(list ,@l))))))
+
+(define (valid-version? v)
+ (let ((d (string-downcase v)))
+ (and (not (string-contains d "dev"))
+ (not (string-contains d "beta"))
+ (not (string-contains d "rc")))))
+
+(define* (composer-fetch name #:key (version #f))
+ "Return a composer-package representation of the Composer metadata for the
+package NAME with optional VERSION, or #f on failure."
+ (let* ((url (string-append (%composer-base-url) "/p/" name ".json"))
+ (packages (and=> (json-fetch url)
+ (lambda (pkg)
+ (let ((pkgs (assoc-ref pkg "packages")))
+ (or (assoc-ref pkgs name) pkg))))))
+ (if packages
+ (json->composer-package
+ (if version
+ (assoc-ref packages version)
+ (cdr
+ (reduce
+ (lambda (new cur-max)
+ (match new
+ (((? valid-version? version) . tail)
+ (if (version>? (fix-version version)
+ (fix-version (car cur-max)))
+ (cons* version tail)
+ cur-max))
+ (_ cur-max)))
+ (cons* "0.0.0" #f)
+ packages))))
+ #f)))
+
+(define (php-package-name name)
+ "Given the NAME of a package on Packagist, return a Guix-compliant name for
+the package."
+ (let ((name (string-join (string-split name #\/) "-")))
+ (if (string-prefix? "php-" name)
+ (snake-case name)
+ (string-append "php-" (snake-case name)))))
+
+(define (make-php-sexp composer-package)
+ "Return the `package' s-expression for a PHP package for the given
+COMPOSER-PACKAGE."
+ (let* ((source (composer-package-source composer-package))
+ (dependencies (map php-package-name
+ (composer-package-require composer-package)))
+ (dev-dependencies (map php-package-name
+ (composer-package-dev-require composer-package)))
+ (git? (equal? (composer-source-type source) "git")))
+ ((if git? call-with-temporary-directory call-with-temporary-output-file)
+ (lambda* (temp #:optional port)
+ (and (if git?
+ (begin
+ (mkdir-p temp)
+ (git-fetch (composer-source-url source)
+ (composer-source-reference source)
+ temp))
+ (url-fetch (composer-source-url source) temp))
+ `(package
+ (name ,(composer-package-name composer-package))
+ (version ,(composer-package-version composer-package))
+ (source
+ (origin
+ ,@(if git?
+ `((method git-fetch)
+ (uri (git-reference
+ (url ,(if (string-suffix?
+ ".git"
+ (composer-source-url source))
+ (string-drop-right
+ (composer-source-url source)
+ (string-length ".git"))
+ (composer-source-url source)))
+ (commit ,(composer-source-reference source))))
+ (file-name (git-file-name name version))
+ (sha256
+ (base32
+ ,(bytevector->nix-base32-string
+ (file-hash* temp)))))
+ `((method url-fetch)
+ (uri ,(composer-source-url source))
+ (sha256 (base32 ,(guix-hash-url temp)))))))
+ (build-system composer-build-system)
+ ,@(if (null? dependencies)
+ '()
+ `((inputs
+ (list ,@(map string->symbol dependencies)))))
+ ,@(if (null? dev-dependencies)
+ '()
+ `((native-inputs
+ (list ,@(map string->symbol dev-dependencies)))))
+ (synopsis "")
+ (description ,(composer-package-description composer-package))
+ (home-page ,(composer-package-homepage composer-package))
+ (license ,(or (composer-package-license composer-package)
+ 'unknown-license!))))))))
+
+(define composer->guix-package
+ (memoize
+ (lambda* (package-name #:key (version #f) #:allow-other-keys)
+ "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the
+`package' s-expression corresponding to that package and its list of
+dependencies, or #f and the empty list on failure."
+ (let ((package (composer-fetch package-name #:version version)))
+ (if package
+ (let* ((dependencies-names (composer-package-require package))
+ (dev-dependencies-names (composer-package-dev-require package)))
+ (values (make-php-sexp package)
+ (append dependencies-names dev-dependencies-names)))
+ (values #f '()))))))
+
+(define (guix-name->composer-name name)
+ "Given a guix package name, return the name of the package in Packagist."
+ (if (string-prefix? "php-" name)
+ (let ((components (string-split (substring name 4) #\-)))
+ (match components
+ ((namespace name ...)
+ (string-append namespace "/" (string-join name "-")))))
+ name))
+
+(define (guix-package->composer-name package)
+ "Given a Composer PACKAGE built from Packagist, return the name of the
+package in Packagist."
+ (let ((upstream-name (assoc-ref
+ (package-properties package)
+ 'upstream-name))
+ (name (package-name package)))
+ (if upstream-name
+ upstream-name
+ (guix-name->composer-name name))))
+
+(define (string->license str)
+ "Convert the string STR into a license object."
+ (or (spdx-string->license str)
+ (match str
+ ("GNU LGPL" 'license:lgpl2.0)
+ ("GPL" 'license:gpl3)
+ ((or "BSD" "BSD License") 'license:bsd-3)
+ ((or "MIT" "MIT license" "Expat license") 'license:expat)
+ ("Public domain" 'license:public-domain)
+ ((or "Apache License, Version 2.0" "Apache 2.0") 'license:asl2.0)
+ (_ 'unknown-license!))))
+
+(define (php-package? package)
+ "Return true if PACKAGE is a PHP package from Packagist."
+ (and
+ (eq? (package-build-system package) composer-build-system)
+ (string-prefix? "php-" (package-name package))))
+
+(define (latest-release package)
+ "Return an <upstream-source> for the latest release of PACKAGE."
+ (let* ((php-name (guix-package->composer-name package))
+ (package (composer-fetch php-name))
+ (version (composer-package-version package))
+ (url (composer-source-url (composer-package-source package))))
+ (upstream-source
+ (package (package-name package))
+ (version version)
+ (urls (list url)))))
+
+(define %composer-updater
+ (upstream-updater
+ (name 'composer)
+ (description "Updater for Composer packages")
+ (pred php-package?)
+ (import latest-release)))
+
+(define* (composer-recursive-import package-name #:optional version)
+ (recursive-import package-name
+ #:version version
+ #:repo->guix-package composer->guix-package
+ #:guix-name php-package-name))
diff --git a/guix/import/cran.scm b/guix/import/cran.scm
index 59c65f9fa5..d7497e6fb9 100644
--- a/guix/import/cran.scm
+++ b/guix/import/cran.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2015-2023 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2015-2024 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2015-2017, 2019-2021, 2023 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2020 Martin Becze <mjbecze@riseup.net>
@@ -55,6 +55,10 @@
#:use-module (guix sets)
#:export (%input-style
+ %bioconductor-version
+ download
+ fetch-description
+
cran->guix-package
bioconductor->guix-package
cran-recursive-import
@@ -81,6 +85,21 @@
(define %input-style
(make-parameter 'variable)) ; or 'specification
+(define (format-inputs inputs)
+ "Generate a sorted list of package inputs from a list of upstream inputs."
+ (map (lambda (input)
+ (case (%input-style)
+ ((specification)
+ `(specification->package ,(upstream-input-name input)))
+ (else
+ ((compose string->symbol
+ upstream-input-downstream-name)
+ input))))
+ (sort inputs
+ (lambda (a b)
+ (string-ci<? (upstream-input-name a)
+ (upstream-input-name b))))))
+
(define (string->licenses license-string license-prefix)
(let ((licenses
(map string-trim-both
@@ -173,17 +192,15 @@ package definition."
(()
'())
((package-inputs ...)
- `((,input-type (list ,@(map (compose string->symbol
- upstream-input-downstream-name)
- package-inputs)))))))
+ `((,input-type (list ,@(format-inputs package-inputs)))))))
(define %cran-url "https://cran.r-project.org/web/packages/")
(define %cran-canonical-url "https://cran.r-project.org/package=")
(define %bioconductor-url "https://bioconductor.org/packages/")
-;; The latest Bioconductor release is 3.17. Bioconductor packages should be
+;; The latest Bioconductor release is 3.18. Bioconductor packages should be
;; updated together.
-(define %bioconductor-version "3.17")
+(define %bioconductor-version "3.18")
(define* (bioconductor-packages-list-url #:optional type)
(string-append "https://bioconductor.org/packages/"
@@ -253,7 +270,7 @@ bioconductor package NAME, or #F if the package is unknown."
;; of the URLs is the /Archive CRAN URL.
(any (cut download-to-store store <>) urls)))))))))
-(define (fetch-description-from-tarball url)
+(define* (fetch-description-from-tarball url #:key (download download))
"Fetch the tarball at URL, extra its 'DESCRIPTION' file, parse it, and
return the resulting alist."
(match (download url)
@@ -271,7 +288,7 @@ return the resulting alist."
(call-with-input-file (string-append dir "/DESCRIPTION")
read-string)))))))))
-(define* (fetch-description repository name #:optional version)
+(define* (fetch-description repository name #:optional version replacement-download)
"Return an alist of the contents of the DESCRIPTION file for the R package
NAME at VERSION in the given REPOSITORY, or #f in case of failure. NAME is
case-sensitive."
@@ -293,7 +310,9 @@ from ~a: ~a (~a)~%")
(string-append "mirror://cran/src/contrib/Archive/"
name "/"
name "_" version ".tar.gz"))))
- (fetch-description-from-tarball urls))
+ (fetch-description-from-tarball
+ urls #:download (or replacement-download
+ download)))
(let* ((url (string-append %cran-url name "/DESCRIPTION"))
(port (http-fetch url))
(result (description->alist (read-string port))))
@@ -310,7 +329,9 @@ from ~a: ~a (~a)~%")
;; TODO: Honor VERSION.
(version (latest-bioconductor-package-version name type))
(url (car (bioconductor-uri name version type)))
- (meta (fetch-description-from-tarball url)))
+ (meta (fetch-description-from-tarball
+ url #:download (or replacement-download
+ download))))
(if (boolean? type)
meta
(cons `(bioconductor-type . ,type) meta))))
@@ -383,7 +404,8 @@ empty list when the FIELD cannot be found."
;; The field for system dependencies is often abused to specify non-package
;; dependencies (such as c++11). This list is used to ignore them.
(define invalid-packages
- (list "c++"
+ (list "build-essential"
+ "c++"
"c++11"
"c++14"
"c++17"
@@ -392,7 +414,9 @@ empty list when the FIELD cannot be found."
"gnu"
"posix.1-2001"
"linux"
+ "libR"
"none"
+ "rtools"
"unix"
"windows"
"xcode"
@@ -410,6 +434,9 @@ empty list when the FIELD cannot be found."
("freetype2" "freetype")
("gettext" "gnu-gettext")
("gmake" "gnu-make")
+ ("h5py" "python-h5py")
+ ("hmmer3" "hmmer")
+ ("leidenalg" "python-leidenalg")
("libarchive-devel" "libarchive")
("libarchive_dev" "libarchive")
("libbz2" "bzip2")
@@ -417,13 +444,27 @@ empty list when the FIELD cannot be found."
("libjpeg" "libjpeg-turbo")
("liblz4" "lz4")
("liblzma" "xz")
+ ("libssl-dev" "openssl")
+ ("libssl_dev" "openssl")
("libzstd" "zstd")
("libxml2-devel" "libxml2")
+ ("libxml2-dev" "libxml2")
("libz" "zlib")
+ ("libz-dev" "zlib")
("mariadb-devel" "mariadb")
("mysql56_dev" "mariadb")
+ ("nodejs" "node")
+ ("numpy" "python-numpy")
+ ("openssl-devel" "openssl")
+ ("openssl@1.1" "openssl-1.1")
+ ("packaging" "python-packaging")
+ ("pandas" "python-pandas")
("pandoc-citeproc" "pandoc")
("python3" "python-3")
+ ("pytorch" "python-pytorch")
+ ("scikit-learn" "python-scikit-learn")
+ ("scipy" "python-scipy")
+ ("sklearn" "python-scikit-learn")
("sqlite3" "sqlite")
("svn" "subversion")
("tcl/tk" "tcl")
@@ -432,6 +473,7 @@ empty list when the FIELD cannot be found."
("x11" "libx11")
("xml2" "libxml2")
("zlib-devel" "zlib")
+ ("zlib1g-dev" "zlib")
(_ sysname)))
(define cran-guix-name (cut guix-name "r-" <>))
diff --git a/guix/import/crate.scm b/guix/import/crate.scm
index 43823d006e..7a25b2243c 100644
--- a/guix/import/crate.scm
+++ b/guix/import/crate.scm
@@ -5,7 +5,8 @@
;;; Copyright © 2021 Nicolas Goaziou <mail@nicolasgoaziou.fr>
;;; Copyright © 2022 Hartmut Goebel <h.goebel@crazy-compilers.com>
;;; Copyright © 2023 Simon Tournier <zimon.toutoune@gmail.com>
-;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2023, 2024 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2023, 2024 David Elsing <david.elsing@posteo.net>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -25,12 +26,15 @@
(define-module (guix import crate)
#:use-module (guix base32)
#:use-module (guix build-system cargo)
+ #:use-module (guix diagnostics)
#:use-module (gcrypt hash)
#:use-module (guix http-client)
+ #:use-module (guix i18n)
#:use-module (guix import json)
#:use-module (guix import utils)
#:use-module (guix memoization)
#:use-module (guix packages)
+ #:use-module (guix read-print)
#:use-module (guix upstream)
#:use-module (guix utils)
#:use-module (gnu packages)
@@ -40,6 +44,7 @@
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-2)
#:use-module (srfi srfi-26)
+ #:use-module (srfi srfi-69)
#:use-module (srfi srfi-71)
#:export (crate->guix-package
guix-package->crate-name
@@ -99,7 +104,7 @@
;; Autoload Guile-Semver so we only have a soft dependency.
(module-autoload! (current-module)
- '(semver) '(string->semver semver->string semver<?))
+ '(semver) '(string->semver semver->string semver<? semver=? semver>?))
(module-autoload! (current-module)
'(semver ranges) '(string->semver-range semver-range-contains?))
@@ -164,16 +169,18 @@ record or #f if it was not found."
(list-matches "^(0+\\.){,2}[0-9]+" version))))
(define* (make-crate-sexp #:key name version cargo-inputs cargo-development-inputs
- home-page synopsis description license build?)
+ home-page synopsis description license build? yanked?)
"Return the `package' s-expression for a rust package with the given NAME,
VERSION, CARGO-INPUTS, CARGO-DEVELOPMENT-INPUTS, HOME-PAGE, SYNOPSIS, DESCRIPTION,
and LICENSE."
(define (format-inputs inputs)
(map
(match-lambda
- ((name version)
+ ((name version yanked)
(list (crate-name->package-name name)
- (version->semver-prefix version))))
+ (if yanked
+ (string-append version "-yanked")
+ (version->semver-prefix version)))))
inputs))
(let* ((port (http-fetch (crate-uri name version)))
@@ -183,6 +190,9 @@ and LICENSE."
(pkg `(package
(name ,guix-name)
(version ,version)
+ ,@(if yanked?
+ `(,(comment "; This version was yanked!\n" #t))
+ '())
(source (origin
(method url-fetch)
(uri (crate-uri ,name version))
@@ -190,6 +200,9 @@ and LICENSE."
(sha256
(base32
,(bytevector->nix-base32-string (port-sha256 port))))))
+ ,@(if yanked?
+ `((properties '((crate-version-yanked? . #t))))
+ '())
(build-system cargo-build-system)
,@(maybe-arguments (append (if build?
'()
@@ -206,7 +219,10 @@ and LICENSE."
((license) license)
(_ `(list ,@license)))))))
(close-port port)
- (package->definition pkg (version->semver-prefix version))))
+ (package->definition pkg
+ (if yanked?
+ (string-append version "-yanked")
+ (version->semver-prefix version)))))
(define (string->license string)
(filter-map (lambda (license)
@@ -217,13 +233,47 @@ and LICENSE."
'unknown-license!)))
(string-split string (string->char-set " /"))))
-(define* (crate->guix-package crate-name #:key version include-dev-deps?
- #:allow-other-keys)
+(define (min-element l less)
+ "Returns the smallest element of l according to less or #f if l is empty."
+
+ (let loop ((curr #f)
+ (remaining l))
+ (if (null-list? remaining)
+ curr
+ (let ((next (car remaining))
+ (remaining (cdr remaining)))
+ (if (and curr
+ (not (less next curr)))
+ (loop curr remaining)
+ (loop next remaining))))))
+
+(define (max-crate-version-of-semver semver-range range)
+ "Returns a <crate-version> of the highest version within the semver range."
+
+ (define (crate->semver crate)
+ (string->semver (crate-version-number crate)))
+
+ (min-element
+ (filter (lambda (crate)
+ (semver-range-contains? semver-range (crate->semver crate)))
+ range)
+ (lambda args
+ (apply semver>? (map crate->semver args)))))
+
+(define (nonyanked-crate-versions crate)
+ "Returns a list of <crate-version>s which are not yanked by upstream."
+ (filter (lambda (entry)
+ (not (crate-version-yanked? entry)))
+ (crate-versions crate)))
+
+(define* (crate->guix-package
+ crate-name
+ #:key version include-dev-deps? allow-yanked? #:allow-other-keys)
"Fetch the metadata for CRATE-NAME from crates.io, and return the
`package' s-expression corresponding to that package, or #f on failure.
When VERSION is specified, convert it into a semver range and attempt to fetch
the latest version matching this semver range; otherwise fetch the latest
-version of CRATE-NAME. If INCLUDE-DEV-DEPS is true then this will also
+version of CRATE-NAME. If INCLUDE-DEV-DEPS is true then this will also
look up the development dependencs for the given crate."
(define (semver-range-contains-string? range version)
@@ -242,63 +292,100 @@ look up the development dependencs for the given crate."
(or version
(crate-latest-version crate))))
- ;; find the highest existing package that fulfills the semver <range>
+ ;; Find the highest existing package that fulfills the semver <range>.
+ ;; Packages previously marked as yanked take lower priority.
(define (find-package-version name range)
(let* ((semver-range (string->semver-range range))
- (versions
- (sort
- (filter (lambda (version)
- (semver-range-contains? semver-range version))
+ (version
+ (min-element
+ (filter (match-lambda ((semver yanked)
+ (and
+ (or allow-yanked? (not yanked))
+ (semver-range-contains? semver-range semver))))
(map (lambda (pkg)
- (string->semver (package-version pkg)))
+ (let ((version (package-version pkg)))
+ (list
+ (string->semver version)
+ (assoc-ref (package-properties pkg)
+ 'crate-version-yanked?))))
(find-packages-by-name
(crate-name->package-name name))))
- semver<?)))
- (and (not (null-list? versions))
- (semver->string (last versions)))))
-
- ;; Find the highest version of a crate that fulfills the semver <range>
- ;; and hasn't been yanked.
+ (match-lambda* (((semver1 yanked1) (semver2 yanked2))
+ (or (and yanked1 (not yanked2))
+ (and (eq? yanked1 yanked2)
+ (semver<? semver1 semver2))))))))
+ (and (not (eq? #f version))
+ (match-let (((semver yanked) version))
+ (list (semver->string semver) yanked)))))
+
+ ;; Find the highest version of a crate that fulfills the semver <range>.
+ ;; If no matching non-yanked version has been found and allow-yanked? is #t,
+ ;; also consider yanked packages.
(define (find-crate-version crate range)
- (let* ((semver-range (string->semver-range range))
- (versions
- (sort
- (filter (lambda (entry)
- (and
- (not (crate-version-yanked? (second entry)))
- (semver-range-contains? semver-range (first entry))))
- (map (lambda (ver)
- (list (string->semver (crate-version-number ver))
- ver))
- (crate-versions crate)))
- (match-lambda* (((semver _) ...)
- (apply semver<? semver))))))
- (and (not (null-list? versions))
- (second (last versions)))))
-
- (define (dependency-name+version dep)
+ (let ((semver-range (string->semver-range range))
+ (versions (nonyanked-crate-versions crate)))
+ (or (and (not (null-list? versions))
+ (max-crate-version-of-semver semver-range versions))
+ (and allow-yanked?
+ (not (null-list? (crate-versions crate)))
+ (max-crate-version-of-semver semver-range
+ (crate-versions crate))))))
+
+ ;; If no non-yanked existing package version was found, check the upstream
+ ;; versions. If a non-yanked upsteam version exists, use it instead,
+ ;; otherwise use the existing package version, provided it exists.
+ (define (dependency-name+version+yanked dep)
(let* ((name (crate-dependency-id dep))
- (req (crate-dependency-requirement dep))
- (existing-version (find-package-version name req)))
- (if existing-version
- (list name existing-version)
+ (req (crate-dependency-requirement dep))
+ (existing-version (find-package-version name req)))
+ (if (and existing-version (not (second existing-version)))
+ (cons name existing-version)
(let* ((crate (lookup-crate* name))
(ver (find-crate-version crate req)))
- (list name
- (crate-version-number ver))))))
+ (if existing-version
+ (if (and ver (not (crate-version-yanked? ver)))
+ (if (semver=? (string->semver (first existing-version))
+ (string->semver (crate-version-number ver)))
+ (begin
+ (warning (G_ "~A: version ~a is no longer yanked~%")
+ name (first existing-version))
+ (cons name existing-version))
+ (list name
+ (crate-version-number ver)
+ (crate-version-yanked? ver)))
+ (begin
+ (warning (G_ "~A: using existing version ~a, which was yanked~%")
+ name (first existing-version))
+ (cons name existing-version)))
+ (begin
+ (unless ver
+ (leave (G_ "~A: no version found for requirement ~a~%") name req))
+ (if (crate-version-yanked? ver)
+ (warning (G_ "~A: imported version ~a was yanked~%")
+ name (crate-version-number ver)))
+ (list name
+ (crate-version-number ver)
+ (crate-version-yanked? ver))))))))
(define version*
(and crate
- (find-crate-version crate version-number)))
+ (or (find-crate-version crate version-number)
+ (leave (G_ "~A: version ~a not found~%") crate-name version-number))))
;; sort and map the dependencies to a list containing
;; pairs of (name version)
(define (sort-map-dependencies deps)
- (sort (map dependency-name+version
+ (sort (map dependency-name+version+yanked
deps)
- (match-lambda* (((name _) ...)
+ (match-lambda* (((name _ _) ...)
(apply string-ci<? name)))))
+ (define (remove-yanked-info deps)
+ (map
+ (match-lambda ((name version yanked)
+ (list name version)))
+ deps))
+
(if (and crate version*)
(let* ((dependencies (crate-version-dependencies version*))
(dep-crates dev-dep-crates (partition normal-dependency? dependencies))
@@ -308,6 +395,7 @@ look up the development dependencs for the given crate."
'())))
(values
(make-crate-sexp #:build? include-dev-deps?
+ #:yanked? (crate-version-yanked? version*)
#:name crate-name
#:version (crate-version-number version*)
#:cargo-inputs cargo-inputs
@@ -324,19 +412,27 @@ look up the development dependencs for the given crate."
#:description (crate-description crate)
#:license (and=> (crate-version-license version*)
string->license))
- (append cargo-inputs cargo-development-inputs)))
+ (append
+ (remove-yanked-info cargo-inputs)
+ (remove-yanked-info cargo-development-inputs))))
(values #f '())))
-(define* (crate-recursive-import crate-name #:key version)
- (recursive-import crate-name
- #:repo->guix-package (lambda* params
- ;; download development dependencies only for the top level package
- (let ((include-dev-deps? (equal? (car params) crate-name))
- (crate->guix-package* (memoize crate->guix-package)))
- (apply crate->guix-package*
- (append params `(#:include-dev-deps? ,include-dev-deps?)))))
- #:version version
- #:guix-name crate-name->package-name))
+(define* (crate-recursive-import
+ crate-name #:key version recursive-dev-dependencies? allow-yanked?)
+ (recursive-import
+ crate-name
+ #:repo->guix-package
+ (let ((crate->guix-package* (memoize crate->guix-package)))
+ (lambda* params
+ ;; download development dependencies only for the top level package
+ (let ((include-dev-deps?
+ (or (equal? (car params) crate-name)
+ recursive-dev-dependencies?)))
+ (apply crate->guix-package*
+ (append params `(#:include-dev-deps? ,include-dev-deps?
+ #:allow-yanked? ,allow-yanked?))))))
+ #:version version
+ #:guix-name crate-name->package-name))
(define (guix-package->crate-name package)
"Return the crate name of PACKAGE."
@@ -352,6 +448,7 @@ look up the development dependencs for the given crate."
(define (crate-name->package-name name)
(guix-name "rust-" name))
+
;;;
;;; Updater
@@ -365,12 +462,20 @@ look up the development dependencs for the given crate."
include a VERSION string to fetch a specific version."
(let* ((crate-name (guix-package->crate-name package))
(crate (lookup-crate crate-name))
- (version (or version (crate-latest-version crate)))
- (url (crate-uri crate-name version)))
- (upstream-source
- (package (package-name package))
- (version version)
- (urls (list url)))))
+ (version (or version
+ (let ((max-crate-version
+ (max-crate-version-of-semver
+ (string->semver-range
+ (string-append "^" (package-version package)))
+ (nonyanked-crate-versions crate))))
+ (and=> max-crate-version
+ crate-version-number)))))
+ (if version
+ (upstream-source
+ (package (package-name package))
+ (version version)
+ (urls (list (crate-uri crate-name version))))
+ #f)))
(define %crate-updater
(upstream-updater
diff --git a/guix/import/go.scm b/guix/import/go.scm
index 0357e6a1eb..dd9298808d 100644
--- a/guix/import/go.scm
+++ b/guix/import/go.scm
@@ -7,6 +7,7 @@
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
;;; Copyright © 2021 Simon Tournier <zimon.toutoune@gmail.com>
+;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -28,6 +29,7 @@
#:use-module (guix git)
#:use-module (guix hash)
#:use-module (guix i18n)
+ #:use-module ((guix utils) #:select (version>?))
#:use-module (guix diagnostics)
#:use-module (guix import utils)
#:use-module (guix import json)
@@ -92,6 +94,11 @@
;;; Code:
+(define (go-package)
+ "Return the 'go' package. This is a lazy reference so that we don't
+depend on (gnu packages golang)."
+ (module-ref (resolve-interface '(gnu packages golang)) 'go))
+
(define http-fetch*
;; Like http-fetch, but memoized and returning the body as a string.
(memoize (lambda args
@@ -293,7 +300,10 @@ comment, or unknown) and is followed by the indicated data."
;; The following directives may all be used solo or in a block
;; RequireSpec = ModulePath Version newline .
- (define-peg-pattern require all (and module-path version EOL))
+ (define-peg-pattern require all
+ (and module-path version
+ ;; We don't want the transitive dependencies.
+ (not-followed-by (and (* WS) "//" (* WS) "indirect")) EOL))
(define-peg-pattern require-top body
(and (ignore "require")
(or (and block-start (* (or require block-line)) block-end) require)))
@@ -310,7 +320,7 @@ comment, or unknown) and is followed by the indicated data."
(define-peg-pattern with all (or (and module-path version) file-path))
(define-peg-pattern replace all (and original => with EOL))
(define-peg-pattern replace-top body
- (and (ignore "replace")
+ (and (ignore "replace")
(or (and block-start (* (or replace block-line)) block-end) replace)))
;; RetractSpec = ( Version | "[" Version "," Version "]" ) newline .
@@ -374,6 +384,17 @@ DIRECTIVE."
;; Prevent inlining of this procedure, which is accessed by unit tests.
(set! go.mod-requirements go.mod-requirements)
+(define (go.mod-go-version go.mod)
+ "Return the minimum version of go required to specified by GO.MOD."
+ (let ((go-version (go.mod-directives go.mod 'go)))
+ (if (null? go-version)
+ ;; If the go directive is missing, go 1.16 is assumed.
+ '(version "1.16")
+ (flatten go-version))))
+
+;; Prevent inlining of this procedure, which is accessed by unit tests.
+(set! go.mod-go-version go.mod-go-version)
+
(define-record-type <vcs>
(%make-vcs url-prefix root-regex type)
vcs?
@@ -606,6 +627,7 @@ When VERSION is unspecified, the latest version available is used."
available-versions
module-path))
(content (fetch-go.mod goproxy module-path version*))
+ (min-go-version (second (go.mod-go-version (parse-go.mod content))))
(dependencies+versions (go.mod-requirements (parse-go.mod content)))
(dependencies (if pin-versions?
dependencies+versions
@@ -630,10 +652,13 @@ When VERSION is unspecified, the latest version available is used."
,(vcs->origin vcs-type vcs-repo-url version*))
(build-system go-build-system)
(arguments
- '(#:import-path ,module-path
- ,@(if (string=? module-path-sans-suffix root-module-path)
- '()
- `(#:unpack-path ,root-module-path))))
+ (list ,@(if (version>? min-go-version (package-version (go-package)))
+ `(#:go ,(string->number min-go-version))
+ '())
+ #:import-path ,module-path
+ ,@(if (string=? module-path-sans-suffix root-module-path)
+ '()
+ `(#:unpack-path ,root-module-path))))
,@(maybe-propagated-inputs
(map (match-lambda
((name version)
diff --git a/guix/import/hackage.scm b/guix/import/hackage.scm
index 9333bedbbd..bbaee73a06 100644
--- a/guix/import/hackage.scm
+++ b/guix/import/hackage.scm
@@ -335,7 +335,7 @@ the hash of the Cabal file."
(synopsis ,(cabal-package-synopsis cabal))
(description ,(beautify-description (cabal-package-description cabal)))
(license ,(string->license (cabal-package-license cabal))))
- inputs)))
+ (map upstream-input-name inputs))))
(define* (hackage->guix-package package-name #:key
(include-test-dependencies? #t)
diff --git a/guix/import/stackage.scm b/guix/import/stackage.scm
index 00814c7d46..f801835b33 100644
--- a/guix/import/stackage.scm
+++ b/guix/import/stackage.scm
@@ -92,7 +92,7 @@
"Return the version of the package with upstream NAME included in PACKAGES."
(let ((pkg (find (lambda (pkg) (string=? (stackage-package-name pkg) name))
packages)))
- (stackage-package-version pkg)))
+ (and=> pkg stackage-package-version)))
;;;
diff --git a/guix/inferior.scm b/guix/inferior.scm
index fca6fb4b22..190ba01b3c 100644
--- a/guix/inferior.scm
+++ b/guix/inferior.scm
@@ -872,14 +872,17 @@ prefix, resolve it; and if 'commit' is unset, fetch CHANNEL's branch tip."
(authenticate? #t)
(cache-directory (%inferior-cache-directory))
(ttl (* 3600 24 30))
- validate-channels)
+ (reference-channels '())
+ (validate-channels (const #t)))
"Return a directory containing a guix filetree defined by CHANNELS, a list of channels.
The directory is a subdirectory of CACHE-DIRECTORY, where entries can be
reclaimed after TTL seconds. This procedure opens a new connection to the
build daemon. AUTHENTICATE? determines whether CHANNELS are authenticated.
-VALIDATE-CHANNELS, if specified, must be a one argument procedure accepting a
-list of channels that can be used to validate the channels; it should raise an
-exception in case of problems."
+
+VALIDATE-CHANNELS must be a four-argument procedure used to validate channel
+instances against REFERENCE-CHANNELS; it is passed as #:validate-pull to
+'latest-channel-instances' and should raise an exception in case a target
+channel commit is deemed \"invalid\"."
(define commits
;; Since computing the instances of CHANNELS is I/O-intensive, use a
;; cheaper way to get the commit list of CHANNELS. This limits overhead
@@ -927,30 +930,31 @@ exception in case of problems."
(if (file-exists? cached)
cached
- (begin
- (when (procedure? validate-channels)
- (validate-channels channels))
- (run-with-store store
- (mlet* %store-monad ((instances
- -> (latest-channel-instances store channels
- #:authenticate?
- authenticate?))
- (profile
- (channel-instances->derivation instances)))
- (mbegin %store-monad
- ;; It's up to the caller to install a build handler to report
- ;; what's going to be built.
- (built-derivations (list profile))
-
- ;; Cache if and only if AUTHENTICATE? is true.
- (if authenticate?
- (mbegin %store-monad
- (symlink* (derivation->output-path profile) cached)
- (add-indirect-root* cached)
- (return cached))
- (mbegin %store-monad
- (add-temp-root* (derivation->output-path profile))
- (return (derivation->output-path profile))))))))))
+ (run-with-store store
+ (mlet* %store-monad ((instances
+ -> (latest-channel-instances store channels
+ #:authenticate?
+ authenticate?
+ #:current-channels
+ reference-channels
+ #:validate-pull
+ validate-channels))
+ (profile
+ (channel-instances->derivation instances)))
+ (mbegin %store-monad
+ ;; It's up to the caller to install a build handler to report
+ ;; what's going to be built.
+ (built-derivations (list profile))
+
+ ;; Cache if and only if AUTHENTICATE? is true.
+ (if authenticate?
+ (mbegin %store-monad
+ (symlink* (derivation->output-path profile) cached)
+ (add-indirect-root* cached)
+ (return cached))
+ (mbegin %store-monad
+ (add-temp-root* (derivation->output-path profile))
+ (return (derivation->output-path profile)))))))))
(define* (inferior-for-channels channels
#:key
diff --git a/guix/least-authority.scm b/guix/least-authority.scm
index bfd7275e7c..3465fe9a48 100644
--- a/guix/least-authority.scm
+++ b/guix/least-authority.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2022 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2022-2023 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -41,6 +41,8 @@
(define* (least-authority-wrapper program
#:key (name "pola-wrapper")
+ (user #f)
+ (group #f)
(guest-uid 1000)
(guest-gid 1000)
(mappings '())
@@ -55,7 +57,11 @@ symbols; it runs with GUEST-UID and GUEST-GID. MAPPINGS is a list of
<file-system-mapping> records indicating directories mirrored inside the
execution environment of PROGRAM. DIRECTORY is the working directory of the
wrapped process. Each environment listed in PRESERVED-ENVIRONMENT-VARIABLES
-is preserved; other environment variables are erased."
+is preserved; other environment variables are erased.
+
+When USER and GROUP are set and NAMESPACES does not include 'user, change UIDs
+and GIDs to these prior to executing PROGRAM. This usually requires that the
+resulting wrapper be executed as root so it can call setgid(2) and setuid(2)."
(define code
(with-imported-modules (source-module-closure
'((gnu system file-systems)
@@ -113,6 +119,10 @@ is preserved; other environment variables are erased."
#$program signal)
(exit (+ 128 signal))))))
+ (define namespaces '#$namespaces)
+ (define host-group '#$group)
+ (define host-user '#$user)
+
;; Note: 'call-with-container' creates a sub-process that this one
;; waits for. This might seem suboptimal but unshare(2) isn't
;; really applicable: the process would still run in the same PID
@@ -123,6 +133,17 @@ is preserved; other environment variables are erased."
(lambda ()
(chdir #$directory)
(environ variables)
+
+ (unless (memq 'user namespaces)
+ ;; This process lives in its parent user namespace,
+ ;; presumably as root; now is the time to setgid/setuid if
+ ;; asked for it (the 'clone' call would fail with EPERM if we
+ ;; changed UIDs/GIDs beforehand).
+ (when host-group
+ (setgid (group:gid (getgr host-group))))
+ (when host-user
+ (setuid (passwd:uid (getpw host-user)))))
+
(apply execl #$program #$program (cdr (command-line))))
;; Don't assume PROGRAM can behave as an init process.
diff --git a/guix/lint.scm b/guix/lint.scm
index 7ccf52dec1..861e352b93 100644
--- a/guix/lint.scm
+++ b/guix/lint.scm
@@ -1857,7 +1857,8 @@ them for PACKAGE."
(call-with-input-file file
(lambda (port)
- (let loop ((line-number 1)
+ (go-to-location port starting-line 0)
+ (let loop ((line-number starting-line)
(last-line #f)
(warnings '()))
(let ((line (read-line port)))
diff --git a/guix/monad-repl.scm b/guix/monad-repl.scm
index 8a6053edd5..d6b39112b7 100644
--- a/guix/monad-repl.scm
+++ b/guix/monad-repl.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2014, 2015, 2016, 2022 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2014-2016, 2022-2023 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -21,13 +21,15 @@
#:use-module (guix monads)
#:use-module (guix utils)
#:use-module (guix packages)
+ #:autoload (guix build-system) (bag)
#:use-module (guix status)
- #:autoload (guix gexp) (lower-object)
+ #:autoload (guix gexp) (gexp gexp? lower-gexp lowered-gexp-sexp lower-object)
#:use-module ((guix derivations)
#:select (derivation?
derivation->output-paths built-derivations))
+ #:autoload (guix read-print) (pretty-print-with-comments)
#:use-module (ice-9 match)
- #:use-module (ice-9 pretty-print)
+ #:autoload (ice-9 pretty-print) (pretty-print)
#:use-module (system repl repl)
#:use-module (system repl common)
#:use-module (system repl command)
@@ -138,4 +140,68 @@ Enter a REPL for values in the store monad."
(repl-option-set! new 'interp #t)
(run-repl new))))
-;;; monad-repl.scm ends here
+
+;;;
+;;; Viewing package arguments.
+;;;
+
+(define (keyword-argument-value args keyword default)
+ "Return the value associated with KEYWORD in ARGS, a keyword/value sequence,
+or DEFAULT if KEYWORD is missing from ARGS."
+ (let loop ((args args))
+ (match args
+ (()
+ default)
+ ((kw value rest ...)
+ (if (eq? kw keyword)
+ value
+ (loop rest))))))
+
+(define (package-argument-command repl form keyword default)
+ "Implement a command that display KEYWORD, a keyword such as #:phases, in
+the arguments of the package FORM evaluates to. Return DEFAULT is KEYWORD is
+missing from those arguments."
+ (match (repl-eval repl form)
+ ((? package? package)
+ (let* ((bag* (bag
+ (inherit (package->bag package))
+ (build (lambda* (name inputs #:rest args)
+ (with-monad %store-monad
+ (return (keyword-argument-value args keyword
+ default))))))))
+ (define phases
+ (parameterize ((%graft? #f))
+ (with-store store
+ (set-build-options store
+ #:print-build-trace #t
+ #:print-extended-build-trace? #t
+ #:multiplexed-build-output? #t)
+ (run-with-store store
+ (mlet %store-monad ((exp (bag->derivation bag*)))
+ (if (gexp? exp)
+ (mlet %store-monad ((gexp (lower-gexp exp)))
+ (return (lowered-gexp-sexp gexp)))
+ (return exp)))))))
+
+ (run-hook before-print-hook phases)
+ (let ((column (port-column (current-output-port))))
+ (pretty-print-with-comments (current-output-port) phases
+ #:indent column)
+ (newline (current-output-port)))))
+ (_
+ (format #t ";; ERROR: This command only accepts package records.~%"))))
+
+(define-meta-command ((phases guix) repl (form))
+ "phases
+Return the build phases of the package defined by FORM."
+ (package-argument-command repl form #:phases #~%standard-phases))
+
+(define-meta-command ((configure-flags guix) repl (form))
+ "configure-flags
+Return the configure flags of the package defined by FORM."
+ (package-argument-command repl form #:configure-flags #~'()))
+
+(define-meta-command ((make-flags guix) repl (form))
+ "make-flags
+Return the make flags of the package defined by FORM."
+ (package-argument-command repl form #:make-flags #~'()))
diff --git a/guix/packages.scm b/guix/packages.scm
index e2e82692ad..930b1a3b0e 100644
--- a/guix/packages.scm
+++ b/guix/packages.scm
@@ -849,14 +849,15 @@ identifiers. The result is inferred from the file names of patches."
'()))))
(append-map patch-vulnerabilities patches)))
-(define (%standard-patch-inputs)
+(define (%standard-patch-inputs system)
(let* ((canonical (module-ref (resolve-interface '(gnu packages base))
'canonical-package))
(ref (lambda (module var)
;; Make sure 'canonical-package' is not influenced by
;; '%current-target-system' since we're going to use the
;; native package anyway.
- (parameterize ((%current-target-system #f))
+ (parameterize ((%current-target-system #f)
+ (%current-system system))
(canonical
(module-ref (resolve-interface module) var))))))
`(("tar" ,(ref '(gnu packages base) 'tar))
@@ -866,7 +867,12 @@ identifiers. The result is inferred from the file names of patches."
("lzip" ,(ref '(gnu packages compression) 'lzip))
("unzip" ,(ref '(gnu packages compression) 'unzip))
("patch" ,(ref '(gnu packages base) 'patch))
- ("locales" ,(ref '(gnu packages base) 'glibc-utf8-locales)))))
+ ("locales"
+ ,(parameterize ((%current-target-system #f)
+ (%current-system system))
+ (canonical
+ ((module-ref (resolve-interface '(gnu packages base))
+ 'libc-utf8-locales-for-target))))))))
(define (default-guile)
"Return the default Guile package used to run the build code of
@@ -909,7 +915,7 @@ specifies modules in scope when evaluating SNIPPET."
(define lookup-input
;; The default value of the 'patch-inputs' field, and thus INPUTS is #f,
;; so deal with that.
- (let ((inputs (or inputs (%standard-patch-inputs))))
+ (let ((inputs (or inputs (%standard-patch-inputs system))))
(lambda (name)
(match (assoc-ref inputs name)
((package) package)
diff --git a/guix/platform.scm b/guix/platform.scm
index 55917ca308..994563ab26 100644
--- a/guix/platform.scm
+++ b/guix/platform.scm
@@ -29,6 +29,7 @@
platform-target
platform-system
platform-linux-architecture
+ platform-rust-target
platform-glibc-dynamic-linker
&platform-not-found-error
@@ -74,6 +75,8 @@
(system platform-system)
(linux-architecture platform-linux-architecture
(default #false))
+ (rust-target platform-rust-target
+ (default #false))
(glibc-dynamic-linker platform-glibc-dynamic-linker))
diff --git a/guix/platforms/arm.scm b/guix/platforms/arm.scm
index 32c0fbc032..b0c76efc73 100644
--- a/guix/platforms/arm.scm
+++ b/guix/platforms/arm.scm
@@ -27,6 +27,7 @@
(target "arm-linux-gnueabihf")
(system "armhf-linux")
(linux-architecture "arm")
+ (rust-target "armv7-unknown-linux-gnueabihf")
(glibc-dynamic-linker "/lib/ld-linux-armhf.so.3")))
(define aarch64-linux
@@ -34,4 +35,5 @@
(target "aarch64-linux-gnu")
(system "aarch64-linux")
(linux-architecture "arm64")
+ (rust-target "aarch64-unknown-linux-gnu")
(glibc-dynamic-linker "/lib/ld-linux-aarch64.so.1")))
diff --git a/guix/platforms/avr.scm b/guix/platforms/avr.scm
new file mode 100644
index 0000000000..ba178db6ea
--- /dev/null
+++ b/guix/platforms/avr.scm
@@ -0,0 +1,28 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2023 Foundation Devices, Inc. <hello@foundationdevices.com>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix platforms avr)
+ #:use-module (guix platform)
+ #:use-module (guix records)
+ #:export (avr))
+
+(define avr
+ (platform
+ (target "avr")
+ (system #f)
+ (glibc-dynamic-linker #f)))
diff --git a/guix/platforms/mips.scm b/guix/platforms/mips.scm
index e6fa9eb292..17b6958f48 100644
--- a/guix/platforms/mips.scm
+++ b/guix/platforms/mips.scm
@@ -26,4 +26,5 @@
(target "mips64el-linux-gnu")
(system "mips64el-linux")
(linux-architecture "mips")
+ (rust-target "mips64el-unknown-linux-gnuabi64")
(glibc-dynamic-linker "/lib/ld.so.1")))
diff --git a/guix/platforms/powerpc.scm b/guix/platforms/powerpc.scm
index 1c7141ab42..c55301768d 100644
--- a/guix/platforms/powerpc.scm
+++ b/guix/platforms/powerpc.scm
@@ -28,6 +28,7 @@
(target "powerpc-linux-gnu")
(system "powerpc-linux")
(linux-architecture "powerpc")
+ (rust-target "powerpc-unknown-linux-gnu")
(glibc-dynamic-linker "/lib/ld.so.1")))
(define powerpc64-linux
@@ -35,6 +36,7 @@
(target "powerpc64-linux-gnu")
(system #f) ;not supported
(linux-architecture "powerpc")
+ (rust-target "powerpc64-unknown-linux-gnu")
(glibc-dynamic-linker "/lib/ld64.so.1")))
(define powerpc64le-linux
@@ -42,4 +44,5 @@
(target "powerpc64le-linux-gnu")
(system "powerpc64le-linux")
(linux-architecture "powerpc")
+ (rust-target "powerpc64le-unknown-linux-gnu")
(glibc-dynamic-linker "/lib/ld64.so.2")))
diff --git a/guix/platforms/riscv.scm b/guix/platforms/riscv.scm
index c716c12c12..1b34e82b36 100644
--- a/guix/platforms/riscv.scm
+++ b/guix/platforms/riscv.scm
@@ -26,4 +26,5 @@
(target "riscv64-linux-gnu")
(system "riscv64-linux")
(linux-architecture "riscv")
+ (rust-target "riscv64gc-unknown-linux-gnu")
(glibc-dynamic-linker "/lib/ld-linux-riscv64-lp64d.so.1")))
diff --git a/guix/platforms/x86.scm b/guix/platforms/x86.scm
index 6f547dd770..0c8fc7296c 100644
--- a/guix/platforms/x86.scm
+++ b/guix/platforms/x86.scm
@@ -1,5 +1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2022 Mathieu Othacehe <othacehe@gnu.org>
+;;; Copyright © 2023, 2024 Efraim Flashner <efraim@flashner.co.il>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -21,6 +22,7 @@
#:use-module (guix records)
#:export (i686-linux
x86_64-linux
+ x86_64-linux-x32
i686-mingw
x86_64-mingw
i586-gnu))
@@ -30,6 +32,7 @@
(target "i686-linux-gnu")
(system "i686-linux")
(linux-architecture "i386")
+ (rust-target "i686-unknown-linux-gnu")
(glibc-dynamic-linker "/lib/ld-linux.so.2")))
(define x86_64-linux
@@ -37,22 +40,34 @@
(target "x86_64-linux-gnu")
(system "x86_64-linux")
(linux-architecture "x86_64")
+ (rust-target "x86_64-unknown-linux-gnu")
(glibc-dynamic-linker "/lib/ld-linux-x86-64.so.2")))
+(define x86_64-linux-x32
+ (platform
+ (target "x86_64-linux-gnux32")
+ (system #f)
+ (linux-architecture "x86_64")
+ (rust-target "x86_64-unknown-linux-gnux32")
+ (glibc-dynamic-linker "/lib/ld-linux-x32.so.2")))
+
(define i686-mingw
(platform
(target "i686-w64-mingw32")
(system #f)
+ (rust-target "i686-pc-windows-gnu")
(glibc-dynamic-linker #f)))
(define x86_64-mingw
(platform
(target "x86_64-w64-mingw32")
(system #f)
+ (rust-target "x86_64-pc-windows-gnu")
(glibc-dynamic-linker #f)))
(define i586-gnu
(platform
(target "i586-pc-gnu")
(system "i586-gnu")
+ (rust-target "i686-unknown-hurd-gnu")
(glibc-dynamic-linker "/lib/ld.so.1")))
diff --git a/guix/profiles.scm b/guix/profiles.scm
index 5d2fb8dc64..ce2f8337bf 100644
--- a/guix/profiles.scm
+++ b/guix/profiles.scm
@@ -1000,8 +1000,9 @@ MANIFEST."
(module-ref (resolve-interface '(gnu packages texinfo)) 'texinfo))
(define gzip ;lazy reference
(module-ref (resolve-interface '(gnu packages compression)) 'gzip))
- (define glibc-utf8-locales ;lazy reference
- (module-ref (resolve-interface '(gnu packages base)) 'glibc-utf8-locales))
+ (define libc-utf8-locales-for-target ;lazy reference
+ (module-ref (resolve-interface '(gnu packages base))
+ 'libc-utf8-locales-for-target))
(define build
(with-imported-modules '((guix build utils))
@@ -1043,7 +1044,8 @@ MANIFEST."
(setenv "PATH" (string-append #+gzip "/bin")) ;for info.gz files
(setenv "GUIX_LOCPATH"
- #+(file-append glibc-utf8-locales "/lib/locale"))
+ #+(file-append (libc-utf8-locales-for-target system)
+ "/lib/locale"))
(mkdir-p (string-append #$output "/share/info"))
(exit (every install-info
@@ -1124,8 +1126,9 @@ MANIFEST. Single-file bundles are required by programs such as Git and Lynx."
;; See <http://lists.gnu.org/archive/html/guix-devel/2015-02/msg00429.html>
;; for a discussion.
- (define glibc-utf8-locales ;lazy reference
- (module-ref (resolve-interface '(gnu packages base)) 'glibc-utf8-locales))
+ (define libc-utf8-locales-for-target ;lazy reference
+ (module-ref (resolve-interface '(gnu packages base))
+ 'libc-utf8-locales-for-target))
(define build
(with-imported-modules '((guix build utils))
@@ -1159,9 +1162,11 @@ MANIFEST. Single-file bundles are required by programs such as Git and Lynx."
;; Some file names in the NSS certificates are UTF-8 encoded so
;; install a UTF-8 locale.
(setenv "LOCPATH"
- (string-append #+glibc-utf8-locales "/lib/locale/"
+ (string-append #+(libc-utf8-locales-for-target system)
+ "/lib/locale/"
#+(version-major+minor
- (package-version glibc-utf8-locales))))
+ (package-version
+ (libc-utf8-locales-for-target system)))))
(setlocale LC_ALL "en_US.utf8")
(match (append-map ca-files '#$(manifest-inputs manifest))
@@ -1999,19 +2004,21 @@ are cross-built for TARGET."
(and (derivation? drv) (gexp-input drv)))
extras))
- (define glibc-utf8-locales ;lazy reference
+ (define libc-utf8-locales-for-target ;lazy reference
(module-ref (resolve-interface '(gnu packages base))
- 'glibc-utf8-locales))
+ 'libc-utf8-locales-for-target))
(define set-utf8-locale
;; Some file names (e.g., in 'nss-certs') are UTF-8 encoded so
;; install a UTF-8 locale.
- #~(begin
- (setenv "LOCPATH"
- #$(file-append glibc-utf8-locales "/lib/locale/"
- (version-major+minor
- (package-version glibc-utf8-locales))))
- (setlocale LC_ALL "en_US.utf8")))
+ (let ((locales (libc-utf8-locales-for-target
+ (or system (%current-system)))))
+ #~(begin
+ (setenv "LOCPATH"
+ #$(file-append locales "/lib/locale/"
+ (version-major+minor
+ (package-version locales))))
+ (setlocale LC_ALL "en_US.utf8"))))
(define builder
(with-imported-modules '((guix build profiles)
diff --git a/guix/progress.scm b/guix/progress.scm
index 33cf6f4a1a..e1b35094e1 100644
--- a/guix/progress.scm
+++ b/guix/progress.scm
@@ -21,6 +21,7 @@
(define-module (guix progress)
#:use-module (guix records)
+ #:autoload (guix build syscalls) (terminal-string-width)
#:use-module (srfi srfi-19)
#:use-module (rnrs io ports)
#:use-module (rnrs bytevectors)
@@ -307,7 +308,7 @@ tasks is performed. Write PREFIX at the beginning of the line."
(if (string-null? prefix)
(display (progress-bar ratio (current-terminal-columns)) port)
(let ((width (- (current-terminal-columns)
- (string-length prefix) 3)))
+ (terminal-string-width prefix) 3)))
(display prefix port)
(display " " port)
(display (progress-bar ratio width) port)))
diff --git a/guix/read-print.scm b/guix/read-print.scm
index 7faad82c94..6421b79737 100644
--- a/guix/read-print.scm
+++ b/guix/read-print.scm
@@ -46,6 +46,7 @@
page-break
page-break?
+ <comment>
comment
comment?
comment->string
@@ -330,6 +331,7 @@ expressions and blanks that were read."
('add-after '(((modify-phases) . 3)))
('add-before '(((modify-phases) . 3)))
('replace '(((modify-phases) . 2))) ;different from 'modify-inputs'
+ ('parameterize 2)
('substitute* 2)
('substitute-keyword-arguments 2)
('call-with-input-file 2)
diff --git a/guix/scripts/challenge.scm b/guix/scripts/challenge.scm
index 01e2f9a2b2..d38171b868 100644
--- a/guix/scripts/challenge.scm
+++ b/guix/scripts/challenge.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2015-2017, 2019-2022 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2015-2017, 2019-2023 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -504,7 +504,6 @@ Challenge the substitutes for PACKAGE... provided by one or more servers.\n"))
(define %default-options
`((system . ,(%current-system))
- (substitute-urls . ,%default-substitute-urls)
(difference-report . ,report-differing-files)))
@@ -539,7 +538,13 @@ Challenge the substitutes for PACKAGE... provided by one or more servers.\n"))
(G_ "no arguments specified, nothing to do~%"))
(exit 0))
(x
- files))))
+ files)))
+ (urls (or urls
+ (substitute-urls store)
+ (begin
+ (warning (G_ "could not determine current \
+substitute URLs; using defaults~%"))
+ %default-substitute-urls))))
(set-build-options store
#:use-substitutes? #f)
diff --git a/guix/scripts/download.scm b/guix/scripts/download.scm
index 0441d3fead..19052d5652 100644
--- a/guix/scripts/download.scm
+++ b/guix/scripts/download.scm
@@ -55,7 +55,7 @@
file))
(define (ensure-valid-store-file-name name)
- "Replace any character not allowed in a stror name by an underscore."
+ "Replace any character not allowed in a store name by an underscore."
(define valid
;; according to nix/libstore/store-api.cc
diff --git a/guix/scripts/edit.scm b/guix/scripts/edit.scm
index ff2d529bcf..b7b4cd2514 100644
--- a/guix/scripts/edit.scm
+++ b/guix/scripts/edit.scm
@@ -64,7 +64,11 @@ Start $VISUAL or $EDITOR to edit the definitions of PACKAGE...\n"))
(define (search-path* path file)
"Like 'search-path' but exit if FILE is not found."
- (let ((absolute-file-name (search-path path file)))
+ (let ((absolute-file-name (or (search-path path file)
+ ;; It could be that FILE is a relative name
+ ;; i.e., not relative to an element of PATH.
+ (and (file-exists? file)
+ file))))
(unless absolute-file-name
;; Shouldn't happen unless somebody fiddled with the 'location' field.
(leave (G_ "file '~a' not found in search path ~s~%")
diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm
index 6ae3b11e39..1d7a6e198d 100644
--- a/guix/scripts/environment.scm
+++ b/guix/scripts/environment.scm
@@ -311,6 +311,9 @@ use '--preserve' instead~%"))
(define (options/resolve-packages store opts)
"Return OPTS with package specification strings replaced by manifest entries
for the corresponding packages."
+ (define system
+ (assoc-ref opts 'system))
+
(define (manifest-entry=? e1 e2)
(and (eq? (manifest-entry-item e1) (manifest-entry-item e2))
(string=? (manifest-entry-output e1)
@@ -327,11 +330,11 @@ for the corresponding packages."
((? package? package)
(if (eq? mode 'ad-hoc-package)
(list (package->manifest-entry* package))
- (manifest-entries (package->development-manifest package))))
+ (manifest-entries (package->development-manifest package system))))
(((? package? package) (? string? output))
(if (eq? mode 'ad-hoc-package)
(list (package->manifest-entry* package output))
- (manifest-entries (package->development-manifest package))))
+ (manifest-entries (package->development-manifest package system))))
((lst ...)
(append-map (cut packages->outputs <> mode) lst))))
@@ -345,7 +348,8 @@ for the corresponding packages."
(('package 'package (? string? spec))
(manifest-entries
(package->development-manifest
- (transform (specification->package+output spec)))))
+ (transform (specification->package+output spec))
+ system)))
(('expression mode str)
;; Add all the outputs of the package STR evaluates to.
(packages->outputs (read/eval str) mode))
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
index 1e8ffd25ec..d2a1cee56e 100644
--- a/guix/scripts/import.scm
+++ b/guix/scripts/import.scm
@@ -47,7 +47,7 @@
(define importers '("gnu" "pypi" "cpan" "hackage" "stackage" "egg" "elpa"
"gem" "go" "cran" "crate" "texlive" "json" "opam"
- "minetest" "elm" "hexpm"))
+ "minetest" "elm" "hexpm" "composer"))
(define (resolve-importer name)
(let ((module (resolve-interface
diff --git a/guix/scripts/import/composer.scm b/guix/scripts/import/composer.scm
new file mode 100644
index 0000000000..412bae6318
--- /dev/null
+++ b/guix/scripts/import/composer.scm
@@ -0,0 +1,107 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2015 David Thompson <davet@gnu.org>
+;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix scripts import composer)
+ #:use-module (guix ui)
+ #:use-module (guix utils)
+ #:use-module (guix scripts)
+ #:use-module (guix import composer)
+ #:use-module (guix scripts import)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-11)
+ #:use-module (srfi srfi-37)
+ #:use-module (srfi srfi-41)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 format)
+ #:export (guix-import-composer))
+
+
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+ '())
+
+(define (show-help)
+ (display (G_ "Usage: guix import composer PACKAGE-NAME
+Import and convert the Composer package for PACKAGE-NAME.\n"))
+ (display (G_ "
+ -h, --help display this help and exit"))
+ (display (G_ "
+ -V, --version display version information and exit"))
+ (display (G_ "
+ -r, --recursive generate package expressions for all Composer packages\
+ that are not yet in Guix"))
+ (newline)
+ (show-bug-report-information))
+
+(define %options
+ ;; Specification of the command-line options.
+ (cons* (option '(#\h "help") #f #f
+ (lambda args
+ (show-help)
+ (exit 0)))
+ (option '(#\V "version") #f #f
+ (lambda args
+ (show-version-and-exit "guix import composer")))
+ (option '(#\r "recursive") #f #f
+ (lambda (opt name arg result)
+ (alist-cons 'recursive #t result)))
+ %standard-import-options))
+
+
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-import-composer . args)
+ (define (parse-options)
+ ;; Return the alist of option values.
+ (args-fold* args %options
+ (lambda (opt name arg result)
+ (leave (G_ "~A: unrecognized option~%") name))
+ (lambda (arg result)
+ (alist-cons 'argument arg result))
+ %default-options))
+
+ (let* ((opts (parse-options))
+ (args (filter-map (match-lambda
+ (('argument . value)
+ value)
+ (_ #f))
+ (reverse opts))))
+ (match args
+ ((package-name)
+ (if (assoc-ref opts 'recursive)
+ (map (match-lambda
+ ((and ('package ('name name) . rest) pkg)
+ `(define-public ,(string->symbol name)
+ ,pkg))
+ (_ #f))
+ (composer-recursive-import package-name))
+ (let ((sexp (composer->guix-package package-name)))
+ (unless sexp
+ (leave (G_ "failed to download meta-data for package '~a'~%")
+ package-name))
+ sexp)))
+ (()
+ (leave (G_ "too few arguments~%")))
+ ((many ...)
+ (leave (G_ "too many arguments~%"))))))
diff --git a/guix/scripts/import/crate.scm b/guix/scripts/import/crate.scm
index 038faa87db..082a973aee 100644
--- a/guix/scripts/import/crate.scm
+++ b/guix/scripts/import/crate.scm
@@ -5,6 +5,7 @@
;;; Copyright © 2019, 2020 Martin Becze <mjbecze@riseup.net>
;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
;;; Copyright © 2023 Simon Tournier <zimon.toutoune@gmail.com>
+;;; Copyright © 2023 David Elsing <david.elsing@posteo.net>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -47,6 +48,13 @@
Import and convert the crates.io package for PACKAGE-NAME.\n"))
(display (G_ "
-r, --recursive import packages recursively"))
+ (display (G_ "
+ --recursive-dev-dependencies
+ include dev-dependencies recursively"))
+ (display (G_ "
+ --allow-yanked
+ allow importing yanked crates if no alternative
+ satisfying the version requirement exists"))
(newline)
(display (G_ "
-h, --help display this help and exit"))
@@ -67,6 +75,12 @@ Import and convert the crates.io package for PACKAGE-NAME.\n"))
(option '(#\r "recursive") #f #f
(lambda (opt name arg result)
(alist-cons 'recursive #t result)))
+ (option '("recursive-dev-dependencies") #f #f
+ (lambda (opt name arg result)
+ (alist-cons 'recursive-dev-dependencies #t result)))
+ (option '("allow-yanked") #f #f
+ (lambda (opt name arg result)
+ (alist-cons 'allow-yanked #t result)))
%standard-import-options))
@@ -92,8 +106,14 @@ Import and convert the crates.io package for PACKAGE-NAME.\n"))
(package-name->name+version spec))
(match (if (assoc-ref opts 'recursive)
- (crate-recursive-import name #:version version)
- (crate->guix-package name #:version version #:include-dev-deps? #t))
+ (crate-recursive-import
+ name #:version version
+ #:recursive-dev-dependencies?
+ (assoc-ref opts 'recursive-dev-dependencies)
+ #:allow-yanked? (assoc-ref opts 'allow-yanked))
+ (crate->guix-package
+ name #:version version #:include-dev-deps? #t
+ #:allow-yanked? (assoc-ref opts 'allow-yanked)))
((or #f '())
(leave (G_ "failed to download meta-data for package '~a'~%")
(if version
diff --git a/guix/scripts/locate.scm b/guix/scripts/locate.scm
index ae64f46896..963ff2bf57 100644
--- a/guix/scripts/locate.scm
+++ b/guix/scripts/locate.scm
@@ -114,14 +114,24 @@ alter table Packages
add column output text;
")))
+;; XXX: missing in guile-sqlite3@0.1.3
+(define SQLITE_BUSY 5)
+
(define (call-with-database file proc)
- (let ((db (sqlite-open file)))
- (dynamic-wind
- (lambda () #t)
- (lambda ()
- (ensure-latest-database-schema db)
- (proc db))
- (lambda () (sqlite-close db)))))
+ (catch 'sqlite-error
+ (lambda ()
+ (let ((db (sqlite-open file)))
+ (dynamic-wind
+ (lambda () #t)
+ (lambda ()
+ (ensure-latest-database-schema db)
+ (proc db))
+ (lambda () (sqlite-close db)))))
+ (lambda (key who code errmsg)
+ (if (= code SQLITE_BUSY)
+ (leave (G_ "~a: database is locked by another process~%")
+ file)
+ (throw key who code errmsg)))))
(define (ensure-latest-database-schema db)
"Ensure DB follows the latest known version of the schema."
@@ -657,7 +667,7 @@ Locate FILE and return the list of packages that contain it.\n"))
files)))
(()
(if (null? files)
- (unless update?
+ (unless (or update? (assoc-ref opts 'clear?))
(leave (G_ "no files to search for~%")))
(leave (N_ "file~{ '~a'~} not found in database '~a'~%"
"files~{ '~a'~} not found in database '~a'~%"
diff --git a/guix/scripts/pack.scm b/guix/scripts/pack.scm
index bdbea49910..3e45c34895 100644
--- a/guix/scripts/pack.scm
+++ b/guix/scripts/pack.scm
@@ -8,6 +8,8 @@
;;; Copyright © 2020, 2021, 2022, 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; Copyright © 2020 Eric Bavier <bavier@posteo.net>
;;; Copyright © 2022 Alex Griffin <a@ajgrf.com>
+;;; Copyright © 2023 Graham James Addis <graham@addis.org.uk>
+;;; Copyright © 2023 Oleg Pykhalov <go.wigust@gmail.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -47,6 +49,7 @@
#:use-module (guix scripts build)
#:use-module (guix transformations)
#:use-module ((guix self) #:select (make-config.scm))
+ #:use-module ((guix docker) #:select (%docker-image-max-layers))
#:use-module (gnu compression)
#:use-module (gnu packages)
#:use-module (gnu packages bootstrap)
@@ -137,7 +140,8 @@ dependencies are registered."
;; Make sure non-ASCII file names are properly handled.
(setenv "GUIX_LOCPATH"
- #+(file-append glibc-utf8-locales "/lib/locale"))
+ #+(file-append (libc-utf8-locales-for-target (%current-system))
+ "/lib/locale"))
(setlocale LC_ALL "en_US.utf8")
(sql-schema #$schema)
@@ -201,6 +205,16 @@ target the profile's @file{bin/env} file:
(leave (G_ "~a: invalid symlink specification~%")
arg))))
+(define (entry-point-argument-spec-option-parser opt name arg result)
+ "A SRFI-37 option parser for the --entry-point-argument option. The spec
+takes multiple occurrences. The entries are used in the exec form for the
+docker entry-point. The values are used as parameters in conjunction with the
+--entry-point option which is used as the first value in the exec form."
+ (let ((entry-point-argument (assoc-ref result 'entry-point-argument)))
+ (alist-cons 'entry-point-argument
+ (append entry-point-argument (list arg))
+ (alist-delete 'entry-point-argument result eq?))))
+
(define (set-utf8-locale profile)
"Configure the environment to use the \"en_US.utf8\" locale provided by the
GLIBC-UT8-LOCALES package."
@@ -209,7 +223,10 @@ GLIBC-UT8-LOCALES package."
(profile-locales? profile))
#~(begin
(setenv "GUIX_LOCPATH"
- #+(file-append glibc-utf8-locales "/lib/locale"))
+ #+(file-append (let-system (system target)
+ (libc-utf8-locales-for-target
+ (or target system)))
+ "/lib/locale"))
(setlocale LC_ALL "en_US.utf8"))
#~(setenv "GUIX_LOCPATH" "unset for tests")))
@@ -502,12 +519,15 @@ added to the pack."
localstatedir?
(symlinks '())
(archiver tar)
- (extra-options '()))
- "Return a derivation to construct a Docker image of PROFILE. The
-image is a tarball conforming to the Docker Image Specification, compressed
-with COMPRESSOR. It can be passed to 'docker load'. If TARGET is true, it
-must a be a GNU triplet and it is used to derive the architecture metadata in
-the image. EXTRA-OPTIONS may contain the IMAGE-TAG keyword argument."
+ (extra-options '())
+ max-layers)
+ "Return a derivation to construct a Docker image of PROFILE. The image is a
+tarball conforming to the Docker Image Specification, compressed with
+COMPRESSOR. It can be passed to 'docker load'. If TARGET is true, it must a
+be a GNU triplet and it is used to derive the architecture metadata in the
+image. EXTRA-OPTIONS may contain the IMAGE-TAG keyword argument. If
+MAX-LAYERS is not false, the image will be splitted in up to MAX-LAYERS
+layers."
(define database
(and localstatedir?
(file-append (store-database (list profile))
@@ -558,10 +578,28 @@ the image. EXTRA-OPTIONS may contain the IMAGE-TAG keyword argument."
`((directory "/tmp" ,(getuid) ,(getgid) #o1777)
,@(append-map symlink->directives '#$symlinks)))
- (setenv "PATH" #+(file-append archiver "/bin"))
+ (define (form-entry-point prefix entry-point entry-point-argument)
+ ;; Construct entry-point parameter for build-docker-image. The
+ ;; first entry is constructed by prefixing the entry-point with
+ ;; the supplied index, subsequent entries are taken from the
+ ;; --entry-point-argument options.
+ (and=> entry-point
+ (lambda (entry-point)
+ (cons* (string-append prefix "/" entry-point)
+ entry-point-argument))))
+
+ (setenv "PATH"
+ (string-join `(#+(file-append archiver "/bin")
+ #+@(if max-layers
+ (list (file-append gzip "/bin"))
+ '()))
+ ":"))
(let-keywords '#$extra-options #f
- ((image-tag #f))
+ ((image-tag #f)
+ (entry-point-argument '())
+ (max-layers #f))
+
(build-docker-image #$output
(map store-info-item
(call-with-input-file "profile"
@@ -574,16 +612,16 @@ the image. EXTRA-OPTIONS may contain the IMAGE-TAG keyword argument."
#:database #+database
#:system (or #$target %host-type)
#:environment environment
- #:entry-point
- #$(and entry-point
- #~(list
- (string-append #$profile "/"
- #$entry-point)))
+ #:entry-point (form-entry-point
+ #$profile
+ #$entry-point
+ entry-point-argument)
#:extra-files directives
#:compressor
#+(compressor-command compressor)
#:creation-time
- (make-time time-utc 0 1)))))))
+ (make-time time-utc 0 1)
+ #:max-layers max-layers))))))
(gexp->derivation (string-append name ".tar"
(compressor-extension compressor))
@@ -1260,6 +1298,8 @@ last resort for relocation."
(debug . 0)
(verbosity . 1)
(symlinks . ())
+ (entry-point-argument . ())
+ (max-layers . ,%docker-image-max-layers)
(compressor . ,(first %compressors))))
(define %formats
@@ -1295,7 +1335,13 @@ last resort for relocation."
rest))))
(define %docker-format-options
- (list (required-option 'image-tag)))
+ (list (required-option 'image-tag)
+ (option '(#\A "entry-point-argument") #t #f
+ entry-point-argument-spec-option-parser)
+ (option '("max-layers") #t #f
+ (lambda (opt name arg result)
+ (alist-cons 'max-layers (string->number* arg)
+ result)))))
(define (show-docker-format-options)
(display (G_ "
@@ -1304,7 +1350,15 @@ last resort for relocation."
(define (show-docker-format-options/detailed)
(display (G_ "
--image-tag=NAME
- Use the given NAME for the Docker image repository"))
+ Use the given NAME for the Docker image repository
+
+ -A, --entry-point-argument=COMMAND/PARAMETER
+ Value(s) to use for the Docker ENTRYPOINT arguments.
+ Multiple instances are accepted. This is only valid
+ in conjunction with the --entry-point option
+
+ --max-layers=N
+ Number of image layers"))
(newline)
(exit 0))
@@ -1615,7 +1669,11 @@ Create a bundle of PACKAGE.\n"))
(extra-options (match pack-format
('docker
(list #:image-tag
- (assoc-ref opts 'image-tag)))
+ (assoc-ref opts 'image-tag)
+ #:entry-point-argument
+ (assoc-ref opts 'entry-point-argument)
+ #:max-layers
+ (assoc-ref opts 'max-layers)))
('deb
(list #:control-file
(process-file-arg opts 'control-file)
diff --git a/guix/scripts/shell.scm b/guix/scripts/shell.scm
index 10ea110fee..0584a7e018 100644
--- a/guix/scripts/shell.scm
+++ b/guix/scripts/shell.scm
@@ -399,9 +399,16 @@ return #f and #f."
((('nesting? . #t) . rest)
(loop rest system file (append specs '("nested guix"))))
((('load . ('package candidate)) . rest)
+ ;; This is 'guix shell -D -f guix.scm'.
(if (and (not file) (null? specs))
(loop rest system candidate specs)
(values #f #f)))
+ ((('load . ('ad-hoc-package candidate)) . rest)
+ ;; When running 'guix shell -f guix.scm', one typically expects
+ ;; 'guix.scm' to be evaluated every time because it may contain
+ ;; references like (local-file "." #:recursive? #t). Thus, disable
+ ;; caching.
+ (values #f #f))
((('manifest . candidate) . rest)
(if (and (not file) (null? specs))
(loop rest system candidate specs)
diff --git a/guix/scripts/size.scm b/guix/scripts/size.scm
index d26ed98388..8a8676a16f 100644
--- a/guix/scripts/size.scm
+++ b/guix/scripts/size.scm
@@ -317,7 +317,8 @@ Report the size of the PACKAGE or STORE-ITEM, with its dependencies.\n"))
;; Turn off grafts because (1) substitute servers do not serve grafted
;; packages, and (2) they do not make any difference on the
;; resulting size.
- (parameterize ((%graft? #f))
+ (parameterize ((%graft? #f)
+ (%current-system system))
(with-store store
(set-build-options store
#:use-substitutes? #t
diff --git a/guix/scripts/style.scm b/guix/scripts/style.scm
index 145cd09881..211980dc1c 100644
--- a/guix/scripts/style.scm
+++ b/guix/scripts/style.scm
@@ -625,6 +625,8 @@ Update package definitions to the latest style.\n"))
opts)))
(unless (eq? format-package-definition style)
(warning (G_ "'--styling' option has no effect in whole-file mode~%")))
+ (when (null? files)
+ (warning (G_ "no files specified, nothing to do~%")))
(for-each format-whole-file files))
(let ((packages (filter-map (match-lambda
(('argument . spec)
diff --git a/guix/scripts/substitute.scm b/guix/scripts/substitute.scm
index 126f0f9c69..37cd08e289 100755
--- a/guix/scripts/substitute.scm
+++ b/guix/scripts/substitute.scm
@@ -635,8 +635,9 @@ way to download the nar."
(let loop ((cache-urls cache-urls))
(match cache-urls
(()
- (leave (G_ "failed to find alternative substitute for '~a'~%")
- (narinfo-path narinfo)))
+ (report-error (G_ "failed to find alternative substitute for '~a'~%")
+ (narinfo-path narinfo))
+ (display "not-found\n" port))
((cache-url rest ...)
(match (lookup-narinfos cache-url
(list (narinfo-path narinfo))
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
index f85b663d64..bf3d2f9044 100644
--- a/guix/scripts/system.scm
+++ b/guix/scripts/system.scm
@@ -58,6 +58,7 @@
#:use-module (guix scripts system reconfigure)
#:use-module (guix build utils)
#:use-module (guix progress)
+ #:use-module ((guix docker) #:select (%docker-image-max-layers))
#:use-module (gnu build image)
#:use-module (gnu build install)
#:autoload (gnu build file-systems)
@@ -1053,6 +1054,8 @@ Some ACTIONS support additional ARGS.\n"))
(newline)
(show-native-build-options-help)
(newline)
+ (show-docker-format-options)
+ (newline)
(display (G_ "
-h, --help display this help and exit"))
(display (G_ "
@@ -1060,12 +1063,21 @@ Some ACTIONS support additional ARGS.\n"))
(newline)
(show-bug-report-information))
+(define %docker-format-options
+ (list (option '("max-layers") #t #f
+ (lambda (opt name arg result)
+ (alist-cons 'max-layers (string->number* arg)
+ result)))))
+
(define %options
;; Specifications of the command-line options.
(cons* (option '(#\h "help") #f #f
(lambda args
(leave-on-EPIPE (show-help))
(exit 0)))
+ (option '("help-docker-format") #f #f
+ (lambda args
+ (show-docker-format-options/detailed)))
(option '(#\V "version") #f #f
(lambda args
(show-version-and-exit "guix system")))
@@ -1154,7 +1166,8 @@ Some ACTIONS support additional ARGS.\n"))
(alist-cons 'list-installed (or arg "") result)))
(append %standard-build-options
%standard-cross-build-options
- %standard-native-build-options)))
+ %standard-native-build-options
+ %docker-format-options)))
(define %default-options
;; Alist of default option values.
@@ -1175,7 +1188,8 @@ Some ACTIONS support additional ARGS.\n"))
(label . #f)
(volatile-image-root? . #f)
(volatile-vm-root? . #t)
- (graph-backend . "graphviz")))
+ (graph-backend . "graphviz")
+ (max-layers . ,%docker-image-max-layers)))
(define (verbosity-level opts)
"Return the verbosity level based on OPTS, the alist of parsed options."
@@ -1183,6 +1197,17 @@ Some ACTIONS support additional ARGS.\n"))
(if (eq? (assoc-ref opts 'action) 'build)
3 1)))
+(define (show-docker-format-options)
+ (display (G_ "
+ --help-docker-format list options specific to the docker image type.")))
+
+(define (show-docker-format-options/detailed)
+ (display (G_ "
+ --max-layers=N
+ Number of image layers"))
+ (newline)
+ (exit 0))
+
;;;
;;; Entry point.
@@ -1245,6 +1270,7 @@ resulting from command-line parsing."
((docker-image) docker-image-type)
(else image-type)))
(image-size (assoc-ref opts 'image-size))
+ (image-max-layers (assoc-ref opts 'max-layers))
(volatile?
(assoc-ref opts 'volatile-image-root?))
(shared-network?
@@ -1258,6 +1284,7 @@ resulting from command-line parsing."
(image-with-label base-image label)
base-image))
(size image-size)
+ (max-layers image-max-layers)
(volatile-root? volatile?)
(shared-network? shared-network?))))
(os (or (image-operating-system image)
diff --git a/guix/scripts/time-machine.scm b/guix/scripts/time-machine.scm
index f31fae7435..2c30fe7cfd 100644
--- a/guix/scripts/time-machine.scm
+++ b/guix/scripts/time-machine.scm
@@ -46,12 +46,6 @@
#:use-module (srfi srfi-71)
#:export (guix-time-machine))
-;;; The required inferiors mechanism relied on by 'guix time-machine' was
-;;; firmed up in v1.0.0; it is the oldest, safest commit that can be travelled
-;;; to.
-(define %oldest-possible-commit
- "6298c3ffd9654d3231a6f25390b056483e8f407c") ;v1.0.0
-
;;;
;;; Command-line options.
@@ -146,6 +140,31 @@ Execute COMMAND ARGS... in an older version of Guix.\n"))
;;;
+;;; Avoiding traveling too far back.
+;;;
+
+;;; The required inferiors mechanism relied on by 'guix time-machine' was
+;;; firmed up in v1.0.0; it is the oldest, safest commit that can be travelled
+;;; to.
+(define %oldest-possible-commit
+ "6298c3ffd9654d3231a6f25390b056483e8f407c") ;v1.0.0
+
+(define %reference-channels
+ (list (channel (inherit %default-guix-channel)
+ (commit %oldest-possible-commit))))
+
+(define (validate-guix-channel channel start commit relation)
+ "Raise an error if CHANNEL is the 'guix' channel and the RELATION of COMMIT
+to %OLDEST-POSSIBLE-COMMIT is not that of an ancestor."
+ (unless (or (not (guix-channel? channel))
+ (memq relation '(ancestor self)))
+ (raise (formatted-message
+ (G_ "cannot travel past commit `~a' from May 1st, 2019")
+ (string-take %oldest-possible-commit 12)))))
+
+
+
+;;;
;;; Entry point.
;;;
@@ -160,44 +179,22 @@ Execute COMMAND ARGS... in an older version of Guix.\n"))
(ref (assoc-ref opts 'ref))
(substitutes? (assoc-ref opts 'substitutes?))
(authenticate? (assoc-ref opts 'authenticate-channels?)))
-
- (define (validate-guix-channel channels)
- "Finds the Guix channel among CHANNELS, and validates that REF as
-captured from the closure, a git reference specification such as a commit hash
-or tag associated to the channel, is valid and new enough to satisfy the 'guix
-time-machine' requirements. If the captured REF variable is #f, the reference
-validate is the one of the Guix channel found in CHANNELS. A
-`formatted-message' condition is raised otherwise."
- (let* ((guix-channel (find guix-channel? channels))
- (guix-channel-commit (channel-commit guix-channel))
- (guix-channel-branch (channel-branch guix-channel))
- (guix-channel-ref (if guix-channel-commit
- `(tag-or-commit . ,guix-channel-commit)
- `(branch . ,guix-channel-branch)))
- (reference (or ref guix-channel-ref))
- (checkout commit relation (update-cached-checkout
- (channel-url guix-channel)
- #:ref reference
- #:starting-commit
- %oldest-possible-commit)))
- (unless (memq relation '(ancestor self))
- (raise (formatted-message
- (G_ "cannot travel past commit `~a' from May 1st, 2019")
- (string-take %oldest-possible-commit 12))))))
-
- (when command-line
- (let* ((directory
- (with-store store
- (with-status-verbosity (assoc-ref opts 'verbosity)
- (with-build-handler (build-notifier #:use-substitutes?
- substitutes?
- #:verbosity
- (assoc-ref opts 'verbosity)
- #:dry-run? #f)
- (set-build-options-from-command-line store opts)
- (cached-channel-instance store channels
- #:authenticate? authenticate?
- #:validate-channels
- validate-guix-channel)))))
- (executable (string-append directory "/bin/guix")))
- (apply execl (cons* executable executable command-line))))))))
+ (if command-line
+ (let* ((directory
+ (with-store store
+ (with-status-verbosity (assoc-ref opts 'verbosity)
+ (with-build-handler (build-notifier #:use-substitutes?
+ substitutes?
+ #:verbosity
+ (assoc-ref opts 'verbosity)
+ #:dry-run? #f)
+ (set-build-options-from-command-line store opts)
+ (cached-channel-instance store channels
+ #:authenticate? authenticate?
+ #:reference-channels
+ %reference-channels
+ #:validate-channels
+ validate-guix-channel)))))
+ (executable (string-append directory "/bin/guix")))
+ (apply execl (cons* executable executable command-line)))
+ (warning (G_ "no command specified; nothing to do~%")))))))
diff --git a/guix/scripts/weather.scm b/guix/scripts/weather.scm
index 140df3435f..2f8985593d 100644
--- a/guix/scripts/weather.scm
+++ b/guix/scripts/weather.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2017-2022 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2017-2023 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2017 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2018 Kyle Meyer <kyle@kyleam.com>
;;; Copyright © 2020 Simon Tournier <zimon.toutoune@gmail.com>
@@ -35,6 +35,8 @@
#:use-module ((guix build utils) #:select (every*))
#:use-module (guix substitutes)
#:use-module (guix narinfo)
+ #:use-module (guix pki)
+ #:autoload (gcrypt pk-crypto) (canonical-sexp->string)
#:use-module (guix http-client)
#:use-module (guix ci)
#:use-module (guix sets)
@@ -185,6 +187,44 @@ or #f if it could not be determined."
(()
#f)))
+(define (check-narinfo-authorization narinfo)
+ "Print a warning when NARINFO is not signed by an authorized key."
+ (define acl
+ (catch 'system-error
+ (lambda ()
+ (current-acl))
+ (lambda args
+ (warning (G_ "could not read '~a': ~a~%")
+ %acl-file (strerror (system-error-errno args)))
+ (warning (G_ "'~a' is unreadable, cannot determine whether \
+substitutes are authorized~%")
+ %acl-file)
+ #f)))
+
+ (unless (or (not acl) (valid-narinfo? narinfo acl))
+ (warning (G_ "substitutes from '~a' are unauthorized~%")
+ (narinfo-uri-base narinfo))
+ ;; The "all substitutes" below reflects the fact that, in reality, it *is*
+ ;; possible to download "unauthorized" substitutes, as long as they match
+ ;; authorized substitutes.
+ (display-hint (G_ "To authorize all substitutes from @uref{~a} to be
+downloaded, the following command needs to be run as root:
+
+@example
+guix archive --authorize <<EOF
+~a
+EOF
+@end example
+
+Alternatively, on Guix System, you can add the signing key above to the
+@code{authorized-keys} field of @code{guix-configuration}.
+
+See \"Getting Substitutes from Other Servers\" in the manual for more
+information.")
+ (narinfo-uri-base narinfo)
+ (canonical-sexp->string
+ (signature-subject (narinfo-signature narinfo))))))
+
(define* (report-server-coverage server items
#:key display-missing?)
"Report the subset of ITEMS available as substitutes on SERVER.
@@ -204,6 +244,12 @@ In case ITEMS is an empty list, return 1 instead."
#:make-progress-reporter
(lambda* (total #:key url #:allow-other-keys)
(progress-reporter/bar total)))))
+ (match narinfos
+ (() #f)
+ ((narinfo . _)
+ ;; Help diagnose missing substitute authorizations.
+ (check-narinfo-authorization narinfo)))
+
(let ((obtained (length narinfos))
(requested (length items))
(missing (lset-difference string=?
@@ -391,7 +437,7 @@ Report the availability of substitutes.\n"))
%standard-native-build-options))
(define %default-options
- `((substitute-urls . ,%default-substitute-urls)))
+ '())
(define (load-manifest file)
"Load the manifest from FILE and return the list of packages it refers to."
@@ -582,7 +628,16 @@ SERVER. Display information for packages with at least THRESHOLD dependents."
(let* ((opts (parse-command-line args %options
(list %default-options)
#:build-options? #f))
- (urls (assoc-ref opts 'substitute-urls))
+ (urls (or (assoc-ref opts 'substitute-urls)
+ (with-store store
+ (substitute-urls store))
+ (begin
+ ;; Could not determine the daemon's current
+ ;; substitute URLs, presumably because it's too
+ ;; old.
+ (warning (G_ "using default \
+substitute URLs~%"))
+ %default-substitute-urls)))
(systems (match (filter-map (match-lambda
(('system . system) system)
(_ #f))
diff --git a/guix/self.scm b/guix/self.scm
index a1f235659d..f378548959 100644
--- a/guix/self.scm
+++ b/guix/self.scm
@@ -73,7 +73,10 @@
("po4a" . ,(ref 'gettext 'po4a))
("gettext-minimal" . ,(ref 'gettext 'gettext-minimal))
("gcc-toolchain" . ,(ref 'commencement 'gcc-toolchain))
- ("glibc-utf8-locales" . ,(ref 'base 'glibc-utf8-locales))
+ ("glibc-utf8-locales" . ,(delay
+ ((module-ref (resolve-interface
+ '(gnu packages base))
+ 'libc-utf8-locales-for-target))))
("graphviz" . ,(ref 'graphviz 'graphviz-minimal))
("font-ghostscript" . ,(ref 'ghostscript 'font-ghostscript))
("texinfo" . ,(ref 'texinfo 'texinfo)))))
diff --git a/guix/store.scm b/guix/store.scm
index f8e77b2cd9..97c4f32a5b 100644
--- a/guix/store.scm
+++ b/guix/store.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012-2022 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012-2023 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2018 Jan Nieuwenhuizen <janneke@gnu.org>
;;; Copyright © 2019, 2020 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2020 Florian Pelz <pelzflorian@pelzflorian.de>
@@ -145,6 +145,7 @@
path-info-nar-size
built-in-builders
+ substitute-urls
references
references/cached
references*
@@ -199,7 +200,7 @@
derivation-log-file
log-file))
-(define %protocol-version #x163)
+(define %protocol-version #x164)
(define %worker-magic-1 #x6e697863) ; "nixc"
(define %worker-magic-2 #x6478696f) ; "dxio"
@@ -253,7 +254,8 @@
(query-valid-derivers 33)
(optimize-store 34)
(verify-store 35)
- (built-in-builders 80))
+ (built-in-builders 80)
+ (substitute-urls 81))
(define-enumerate-type hash-algo
;; hash.hh
@@ -1780,6 +1782,16 @@ The result is always the empty list unless the daemon was started with
This makes sense only when the daemon was started with '--cache-failures'."
boolean)
+(define substitute-urls
+ (let ((urls (operation (substitute-urls)
+ #f
+ string-list)))
+ (lambda (store)
+ "Return the list of currently configured substitutes URLs for STORE, or
+#f if the daemon is too old and does not implement this RPC."
+ (and (>= (store-connection-version store) #x164)
+ (urls store)))))
+
;;;
;;; Per-connection caches.
diff --git a/guix/transformations.scm b/guix/transformations.scm
index 9cba6bedab..132ccd957a 100644
--- a/guix/transformations.scm
+++ b/guix/transformations.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2021 Marius Bakke <marius@gnu.org>
;;; Copyright © 2023 Sarthak Shah <shahsarthakw@gmail.com>
;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2023 Ekaitz Zarraga <ekaitz@elenq.tech>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -439,7 +440,8 @@ the equal sign."
actual compiler."
(define wrapper
#~(begin
- (use-modules (ice-9 match))
+ (use-modules (ice-9 match)
+ (ice-9 string-fun))
(define psabi #$(gcc-architecture->micro-architecture-level
micro-architecture))
@@ -486,11 +488,20 @@ actual compiler."
(apply
execl next
(append (cons next arguments)
- (if (and (search-next "go")
- (string=? next (search-next "go")))
- '()
- (list (string-append "-march="
- #$micro-architecture)))))))))))
+ (cond
+ ((and (search-next "go")
+ (string=? next (search-next "go")))
+ '())
+ ((and (search-next "zig")
+ (string=? next (search-next "zig")))
+ `(,(string-append
+ ;; https://issues.guix.gnu.org/67075#3
+ "-Dcpu="
+ (string-replace-substring
+ #$micro-architecture "-" "_"))))
+ (else
+ (list (string-append "-march="
+ #$micro-architecture))))))))))))
(define program
(program-file (string-append "tuning-compiler-wrapper-" micro-architecture)
@@ -508,7 +519,7 @@ actual compiler."
(symlink #$program
(string-append bin "/" program)))
'("cc" "gcc" "clang" "g++" "c++" "clang++"
- "go")))))))
+ "go" "zig")))))))
(define (build-system-with-tuning-compiler bs micro-architecture)
"Return a variant of BS, a build system, that ensures that the compiler that
diff --git a/guix/ui.scm b/guix/ui.scm
index e3bf07212f..962d291d2e 100644
--- a/guix/ui.scm
+++ b/guix/ui.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012-2023 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012-2024 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>
@@ -555,7 +555,7 @@ See the \"Application Setup\" section in the manual, for more info.\n"))
(leave-on-EPIPE
(simple-format #t "~a (~a) ~a~%"
command %guix-package-name %guix-version)
- (format #t "Copyright ~a 2023 ~a"
+ (format #t "Copyright ~a 2024 ~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. */
diff --git a/guix/utils.scm b/guix/utils.scm
index 7a42b49df2..e4e9d922e7 100644
--- a/guix/utils.scm
+++ b/guix/utils.scm
@@ -7,7 +7,7 @@
;;; Copyright © 2015 David Thompson <davet@gnu.org>
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2018, 2020 Marius Bakke <marius@gnu.org>
-;;; Copyright © 2020, 2021 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2020, 2021, 2024 Efraim Flashner <efraim@flashner.co.il>
;;; Copyright © 2020, 2021, 2022 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; Copyright © 2021 Simon Tournier <zimon.toutoune@gmail.com>
;;; Copyright © 2021 Chris Marusich <cmmarusich@gmail.com>
@@ -19,6 +19,7 @@
;;; Copyright © 2023 Philip McGrath <philip@philipmcgrath.com>
;;; Copyright © 2023 Janneke Nieuwenhuizen <janneke@gnu.org>
;;; Copyright © 2023 Zheng Junjie <873216071@qq.com>
+;;; Copyright © 2023 Foundation Devices, Inc. <hello@foundationdevices.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -96,9 +97,11 @@
target-x86-32?
target-x86-64?
target-x86?
+ target-x32?
target-arm32?
target-aarch64?
target-arm?
+ target-avr?
target-ppc32?
target-ppc64le?
target-powerpc?
@@ -632,6 +635,8 @@ returned by `config.guess'."
(else triplet))))
(cond ((string-match "^arm[^-]*-([^-]+-)?linux-gnueabihf" triplet)
"armhf-linux")
+ ;; Otherwise it will show up as x86_64-linux... which isn't wrong.
+ ((string-match "x86_64-linux-gnux32" triplet) "x86_64-linux-gnux32")
((string-match "^([^-]+)-([^-]+-)?linux-gnu.*" triplet)
=>
(lambda (m)
@@ -708,6 +713,13 @@ a character other than '@'."
architecture (x86_64)?"
(string-prefix? "x86_64-" target))
+(define* (target-x32? #:optional (target (or (%current-target-system)
+ (%current-system))))
+ "Is the architecture of TARGET a variant of Intel/AMD's 64-bit
+architecture (x86_64) using 32-bit data types?"
+ (and (target-x86-64? target)
+ (string-suffix? "gnux32" target)))
+
(define* (target-x86? #:optional (target (or (%current-target-system)
(%current-system))))
(or (target-x86-32? target) (target-x86-64? target)))
@@ -724,6 +736,10 @@ architecture (x86_64)?"
(%current-system))))
(or (target-arm32? target) (target-aarch64? target)))
+(define* (target-avr? #:optional (target (%current-target-system)))
+ "Is the architecture of TARGET a variant of Microchip's AVR architecture?"
+ (or (string=? target "avr") (string-prefix? "avr-" target)))
+
(define* (target-ppc32? #:optional (target (or (%current-target-system)
(%current-system))))
(string-prefix? "powerpc-" target))