From 5291fd7a4205394b863a8705b32fbb447321dc60 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Thu, 20 May 2021 15:40:55 +0200 Subject: records: Support field sanitizers. * guix/records.scm (make-syntactic-constructor): Add #:sanitizers. [field-sanitizer]: New procedure. [wrap-field-value]: Honor F's sanitizer. (define-record-type*)[field-sanitizer]: New procedure. Pass #:sanitizer to 'make-syntactic-constructor'. * tests/records.scm ("define-record-type* & sanitize") ("define-record-type* & sanitize & thunked"): New tests. --- guix/records.scm | 65 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 14 deletions(-) (limited to 'guix') diff --git a/guix/records.scm b/guix/records.scm index 3d54a51956..ed94c83dac 100644 --- a/guix/records.scm +++ b/guix/records.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès +;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès ;;; Copyright © 2018 Mark H Weaver ;;; ;;; This file is part of GNU Guix. @@ -120,7 +120,8 @@ context of the definition of a thunked field." "Make the syntactic constructor NAME for TYPE, that calls CTOR, and expects all of EXPECTED fields to be initialized. DEFAULTS is the list of FIELD/DEFAULT-VALUE tuples, THUNKED is the list of identifiers of thunked -fields, and DELAYED is the list of identifiers of delayed fields. +fields, DELAYED is the list of identifiers of delayed fields, and SANITIZERS +is the list of FIELD/SANITIZER tuples. ABI-COOKIE is the cookie (an integer) against which to check the run-time ABI of TYPE matches the expansion-time ABI." @@ -130,6 +131,7 @@ of TYPE matches the expansion-time ABI." #:this-identifier this-identifier #:delayed delayed #:innate innate + #:sanitizers sanitizers #:defaults defaults) (define-syntax name (lambda (s) @@ -169,19 +171,30 @@ of TYPE matches the expansion-time ABI." (define (innate-field? f) (memq (syntax->datum f) 'innate)) + (define field-sanitizer + (let ((lst (map (match-lambda + ((f p) + (list (syntax->datum f) p))) + #'sanitizers))) + (lambda (f) + (or (and=> (assoc-ref lst (syntax->datum f)) car) + #'(lambda (x) x))))) + (define (wrap-field-value f value) - (cond ((thunked-field? f) - #`(lambda (x) - (syntax-parameterize ((#,this-identifier - (lambda (s) - (syntax-case s () - (id - (identifier? #'id) - #'x))))) - #,value))) - ((delayed-field? f) - #`(delay #,value)) - (else value))) + (let* ((sanitizer (field-sanitizer f)) + (value #`(#,sanitizer #,value))) + (cond ((thunked-field? f) + #`(lambda (x) + (syntax-parameterize ((#,this-identifier + (lambda (s) + (syntax-case s () + (id + (identifier? #'id) + #'x))))) + #,value))) + ((delayed-field? f) + #`(delay #,value)) + (else value)))) (define default-values ;; List of symbol/value tuples. @@ -291,6 +304,19 @@ can access the record it belongs to via the 'this-thing' identifier. A field can also be marked as \"delayed\" instead of \"thunked\", in which case its value is effectively wrapped in a (delay …) form. +A field can also have an associated \"sanitizer\", which is a procedure that +takes a user-supplied field value and returns a \"sanitized\" value for the +field: + + (define-record-type* thing make-thing + thing? + this-thing + (name thing-name + (sanitize (lambda (value) + (cond ((string? value) value) + ((symbol? value) (symbol->string value)) + (else (throw 'bad! value))))))) + It is possible to copy an object 'x' created with 'thing' like this: (thing (inherit x) (name \"bar\")) @@ -307,6 +333,14 @@ inherited." (field-default-value #'(field properties ...))) (_ #f))) + (define (field-sanitizer s) + (syntax-case s (sanitize) + ((field (sanitize proc) _ ...) + (list #'field #'proc)) + ((field _ properties ...) + (field-sanitizer #'(field properties ...))) + (_ #f))) + (define-field-property-predicate delayed-field? delayed) (define-field-property-predicate thunked-field? thunked) (define-field-property-predicate innate-field? innate) @@ -376,6 +410,8 @@ inherited." (innate (filter-map innate-field? field-spec)) (defaults (filter-map field-default-value #'((field properties ...) ...))) + (sanitizers (filter-map field-sanitizer + #'((field properties ...) ...))) (cookie (compute-abi-cookie field-spec))) (with-syntax (((field-spec* ...) (map field-spec->srfi-9 field-spec)) @@ -421,6 +457,7 @@ of a record instantiation" #:this-identifier #'this-identifier #:delayed #,delayed #:innate #,innate + #:sanitizers #,sanitizers #:defaults #,defaults))))) ((_ type syntactic-ctor ctor pred (field get properties ...) ...) -- cgit v1.2.3 From 613a9c7cb3419d2301cd4748cd0db90e880278c5 Mon Sep 17 00:00:00 2001 From: Brice Waegeneire Date: Wed, 4 Aug 2021 16:59:40 +0200 Subject: import: gem: Fix typo. * guix/scripts/import/gem.scm (%options): Fix typo. --- guix/scripts/import/gem.scm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'guix') diff --git a/guix/scripts/import/gem.scm b/guix/scripts/import/gem.scm index 65d2bf10b4..328d20b946 100644 --- a/guix/scripts/import/gem.scm +++ b/guix/scripts/import/gem.scm @@ -2,6 +2,7 @@ ;;; Copyright © 2015 David Thompson ;;; Copyright © 2018 Oleg Pykhalov ;;; Copyright © 2021 Sarah Morgensen +;;; Copyright © 2021 Brice Waegeneire ;;; ;;; This file is part of GNU Guix. ;;; @@ -60,7 +61,7 @@ Import and convert the RubyGems package for PACKAGE-NAME.\n")) (exit 0))) (option '(#\V "version") #f #f (lambda args - (show-version-and-exit "guix import pypi"))) + (show-version-and-exit "guix import gem"))) (option '(#\r "recursive") #f #f (lambda (opt name arg result) (alist-cons 'recursive #t result))) -- cgit v1.2.3 From 3df485152c545dc365c757368863c6f80815d9ec Mon Sep 17 00:00:00 2001 From: Maxime Devos Date: Tue, 10 Aug 2021 17:07:18 +0200 Subject: build-system: Add 'minetest-mod-build-system'. * guix/build-system/minetest.scm: New module. * guix/build/minetest-build-system.scm: Likewise. * Makefile.am (MODULES): Add them. * doc/guix.texi (Build Systems): Document 'minetest-mod-build-system'. Signed-off-by: Leo Prikler --- Makefile.am | 2 + doc/guix.texi | 8 ++ guix/build-system/minetest.scm | 99 +++++++++++++++ guix/build/minetest-build-system.scm | 229 +++++++++++++++++++++++++++++++++++ 4 files changed, 338 insertions(+) create mode 100644 guix/build-system/minetest.scm create mode 100644 guix/build/minetest-build-system.scm (limited to 'guix') diff --git a/Makefile.am b/Makefile.am index 5542aa1c56..344b7423c5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -141,6 +141,7 @@ MODULES = \ guix/build-system/go.scm \ guix/build-system/meson.scm \ guix/build-system/minify.scm \ + guix/build-system/minetest.scm \ guix/build-system/asdf.scm \ guix/build-system/copy.scm \ guix/build-system/glib-or-gtk.scm \ @@ -203,6 +204,7 @@ MODULES = \ guix/build/gnu-dist.scm \ guix/build/guile-build-system.scm \ guix/build/maven-build-system.scm \ + guix/build/minetest-build-system.scm \ guix/build/node-build-system.scm \ guix/build/perl-build-system.scm \ guix/build/python-build-system.scm \ diff --git a/doc/guix.texi b/doc/guix.texi index 17ecc3ad0f..d6197d3743 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -7895,6 +7895,14 @@ declaration. Its default value is @code{(default-maven-plugins)} which is also exported. @end defvr +@defvr {Scheme Variable} minetest-mod-build-system +This variable is exported by @code{(guix build-system minetest)}. It +implements a build procedure for @uref{https://www.minetest.net, Minetest} +mods, which consists of copying Lua code, images and other resources to +the location Minetest searches for mods. The build system also minimises +PNG images and verifies that Minetest can load the mod without errors. +@end defvr + @defvr {Scheme Variable} minify-build-system This variable is exported by @code{(guix build-system minify)}. It implements a minification procedure for simple JavaScript packages. diff --git a/guix/build-system/minetest.scm b/guix/build-system/minetest.scm new file mode 100644 index 0000000000..f33e97559d --- /dev/null +++ b/guix/build-system/minetest.scm @@ -0,0 +1,99 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2021 Maxime Devos +;;; +;;; 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 . + +(define-module (guix build-system minetest) + #:use-module (guix build-system copy) + #:use-module (guix build-system gnu) + #:use-module (guix build-system) + #:use-module (guix utils) + #:export (minetest-mod-build-system)) + +;; +;; Build procedure for minetest mods. This is implemented as an extension +;; of ‘copy-build-system’. +;; +;; Code: + +;; Lazily resolve the bindings to avoid circular dependencies. +(define (default-optipng) + ;; Lazily resolve the binding to avoid a circular dependency. + (module-ref (resolve-interface '(gnu packages image)) 'optipng)) + +(define (default-minetest) + (module-ref (resolve-interface '(gnu packages games)) 'minetest)) + +(define (default-xvfb-run) + (module-ref (resolve-interface '(gnu packages xorg)) 'xvfb-run)) + +(define %minetest-build-system-modules + ;; Build-side modules imported by default. + `((guix build minetest-build-system) + ,@%copy-build-system-modules)) + +(define %default-modules + ;; Modules in scope in the build-side environment. + '((guix build gnu-build-system) + (guix build minetest-build-system) + (guix build utils))) + +(define (standard-minetest-packages) + "Return the list of (NAME PACKAGE OUTPUT) or (NAME PACKAGE) tuples of +standard packages used as implicit inputs of the Minetest build system." + `(("xvfb-run" ,(default-xvfb-run)) + ("optipng" ,(default-optipng)) + ("minetest" ,(default-minetest)) + ,@(filter (lambda (input) + (member (car input) + '("libc" "tar" "gzip" "bzip2" "xz" "locales"))) + (standard-packages)))) + +(define* (lower-mod name #:key (implicit-inputs? #t) #:allow-other-keys + #:rest arguments) + (define lower (build-system-lower gnu-build-system)) + (apply lower + name + (substitute-keyword-arguments arguments + ;; minetest-mod-build-system adds implicit inputs by itself, + ;; so don't let gnu-build-system add its own implicit inputs + ;; as well. + ((#:implicit-inputs? implicit-inputs? #t) + #f) + ((#:implicit-cross-inputs? implicit-cross-inputs? #t) + #f) + ((#:imported-modules imported-modules %minetest-build-system-modules) + imported-modules) + ((#:modules modules %default-modules) + modules) + ((#:phases phases '%standard-phases) + phases) + ;; Ensure nothing sneaks into the closure. + ((#:allowed-references allowed-references '()) + allowed-references) + ;; Add the implicit inputs. + ((#:native-inputs native-inputs '()) + (if implicit-inputs? + (append native-inputs (standard-minetest-packages)) + native-inputs))))) + +(define minetest-mod-build-system + (build-system + (name 'minetest-mod) + (description "The build system for minetest mods") + (lower lower-mod))) + +;;; minetest.scm ends here diff --git a/guix/build/minetest-build-system.scm b/guix/build/minetest-build-system.scm new file mode 100644 index 0000000000..477cc3d1d0 --- /dev/null +++ b/guix/build/minetest-build-system.scm @@ -0,0 +1,229 @@ +;;; Copyright © 2021 Maxime Devos +;;; +;;; 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 . + +(define-module (guix build minetest-build-system) + #:use-module (guix build utils) + #:use-module (srfi srfi-1) + #:use-module (ice-9 format) + #:use-module (ice-9 match) + #:use-module (ice-9 rdelim) + #:use-module (ice-9 receive) + #:use-module (ice-9 regex) + #:use-module ((guix build gnu-build-system) #:prefix gnu:) + #:use-module ((guix build copy-build-system) #:prefix copy:) + #:export (%standard-phases + mod-install-plan minimise-png read-mod-name check)) + +;; (guix build copy-build-system) does not export 'install'. +(define copy:install + (assoc-ref copy:%standard-phases 'install)) + +(define (mod-install-plan mod-name) + `(("." ,(string-append "share/minetest/mods/" mod-name) + ;; Only install files that will actually be used at run time. + ;; This can save a little disk space. + ;; + ;; See + ;; for an incomple list of files that can be found in mods. + #:include ("mod.conf" "modpack.conf" "settingtypes.txt" "depends.txt" + "description.txt") + #:include-regexp (".lua$" ".png$" ".ogg$" ".obj$" ".b3d$" ".tr$" + ".mts$")))) + +(define* (guess-mod-name #:key inputs #:allow-other-keys) + "Try to determine the name of the mod or modpack that is being built. +If it is unknown, make an educated guess." + ;; Minetest doesn't care about the directory names in "share/minetest/mods" + ;; so there is no technical problem if the directory names don't match + ;; the mod names. The directory can appear in the GUI if the modpack + ;; doesn't have the 'name' set though, so try to make a guess. + (define (guess) + (let* ((source (assoc-ref inputs "source")) + ;; Don't retain a reference to the store. + (file-name (strip-store-file-name source)) + ;; The "minetest-" prefix is not informative, so strip it. + (file-name (if (string-prefix? "minetest-" file-name) + (substring file-name (string-length "minetest-")) + file-name)) + ;; Strip "-checkout" suffixes of git checkouts. + (file-name (if (string-suffix? "-checkout" file-name) + (substring file-name + 0 + (- (string-length file-name) + (string-length "-checkout"))) + file-name)) + (first-dot (string-index file-name #\.)) + ;; If the source code is in an archive (.tar.gz, .zip, ...), + ;; strip the extension. + (file-name (if first-dot + (substring file-name 0 first-dot) + file-name))) + (format (current-error-port) + "warning: the modpack ~a did not set 'name' in 'modpack.conf'~%" + file-name) + file-name)) + (cond ((file-exists? "mod.conf") + ;; Mods must have 'name' set in "mod.conf", so don't guess. + (read-mod-name "mod.conf")) + ((file-exists? "modpack.conf") + ;; While it is recommended to have 'name' set in 'modpack.conf', + ;; it is optional, so guess a name if necessary. + (read-mod-name "modpack.conf" guess)) + (#t (guess)))) + +(define* (install #:key inputs #:allow-other-keys #:rest arguments) + (apply copy:install + #:install-plan (mod-install-plan (apply guess-mod-name arguments)) + arguments)) + +(define %png-magic-bytes + ;; Magic bytes of PNG images, see ‘5.2 PNG signatures’ in + ;; ‘Portable Network Graphics (PNG) Specification (Second Edition)’ + ;; on . + #vu8(137 80 78 71 13 10 26 10)) + +(define png-file? + ((@@ (guix build utils) file-header-match) %png-magic-bytes)) + +(define* (minimise-png #:key inputs native-inputs #:allow-other-keys) + "Minimise PNG images found in the working directory." + (define optipng (which "optipng")) + (define (optimise image) + (format #t "Optimising ~a~%" image) + (make-file-writable (dirname image)) + (make-file-writable image) + (define old-size (stat:size (stat image))) + ;; The mod "technic" has a file "technic_music_player_top.png" that + ;; actually is a JPEG file, see + ;; . + (if (png-file? image) + (invoke optipng "-o4" "-quiet" image) + (format #t "warning: skipping ~a because it's not actually a PNG image~%" + image)) + (define new-size (stat:size (stat image))) + (values old-size new-size)) + (define files (find-files "." ".png$")) + (let loop ((total-old-size 0) + (total-new-size 0) + (images (find-files "." ".png$"))) + (cond ((pair? images) + (receive (old-size new-size) + (optimise (car images)) + (loop (+ total-old-size old-size) + (+ total-new-size new-size) + (cdr images)))) + ((= total-old-size 0) + (format #t "There were no PNG images to minimise.")) + (#t + (format #t "Minimisation reduced size of images by ~,2f% (~,2f MiB to ~,2f MiB)~%" + (* 100.0 (- 1 (/ total-new-size total-old-size))) + (/ total-old-size (expt 1024 2)) + (/ total-new-size (expt 1024 2))))))) + +(define name-regexp (make-regexp "^name[ ]*=(.+)$")) + +(define* (read-mod-name mod.conf #:optional not-found) + "Read the name of a mod from MOD.CONF. If MOD.CONF +does not have a name field and NOT-FOUND is #false, raise an +error. If NOT-FOUND is TRUE, call NOT-FOUND instead." + (call-with-input-file mod.conf + (lambda (port) + (let loop () + (define line (read-line port)) + (if (eof-object? line) + (if not-found + (not-found) + (error "~a does not have a 'name' field" mod.conf)) + (let ((match (regexp-exec name-regexp line))) + (if (regexp-match? match) + (string-trim-both (match:substring match 1) #\ ) + (loop)))))))) + +(define* (check #:key outputs tests? #:allow-other-keys) + "Test whether the mod loads. The mod must first be installed first." + (define (all-mod-names directories) + (append-map + (lambda (directory) + (map read-mod-name (find-files directory "mod.conf"))) + directories)) + (when tests? + (mkdir "guix_testworld") + ;; Add the mod to the mod search path, such that Minetest can find it. + (setenv "MINETEST_MOD_PATH" + (list->search-path-as-string + (cons + (string-append (assoc-ref outputs "out") "/share/minetest/mods") + (search-path-as-string->list + (or (getenv "MINETEST_MOD_PATH") ""))) + ":")) + (with-directory-excursion "guix_testworld" + (setenv "HOME" (getcwd)) + ;; Create a world in which all mods are loaded. + (call-with-output-file "world.mt" + (lambda (port) + (display + "gameid = minetest +world_name = guix_testworld +backend = sqlite3 +player_backend = sqlite3 +auth_backend = sqlite3 +" port) + (for-each + (lambda (mod) + (format port "load_mod_~a = true~%" mod)) + (all-mod-names (search-path-as-string->list + (getenv "MINETEST_MOD_PATH")))))) + (receive (port pid) + ((@@ (guix build utils) open-pipe-with-stderr) + "xvfb-run" "--" "minetest" "--info" "--world" "." "--go") + (format #t "Started Minetest with all mods loaded for testing~%") + ;; Scan the output for error messages. + ;; When the player has joined the server, stop minetest. + (define (error? line) + (and (string? line) + (string-contains line ": ERROR["))) + (define (stop? line) + (and (string? line) + (string-contains line "ACTION[Server]: singleplayer [127.0.0.1] joins game."))) + (let loop () + (match (read-line port) + ((? error? line) + (error "minetest raised an error: ~a" line)) + ((? stop?) + (kill pid SIGINT) + (close-port port) + (waitpid pid)) + ((? string? line) + (display line) + (newline) + (loop)) + ((? eof-object?) + (error "minetest didn't start")))))))) + +(define %standard-phases + (modify-phases gnu:%standard-phases + (delete 'bootstrap) + (delete 'configure) + (add-before 'build 'minimise-png minimise-png) + (delete 'build) + (delete 'check) + (replace 'install install) + ;; The 'check' phase requires the mod to be installed, + ;; so move the 'check' phase after the 'install' phase. + (add-after 'install 'check check))) + +;;; minetest-build-system.scm ends here -- cgit v1.2.3 From d08455934c937fdd781e51da9a3f211bbdd8192d Mon Sep 17 00:00:00 2001 From: Maxime Devos Date: Tue, 10 Aug 2021 17:07:19 +0200 Subject: import/utils: Recognise GPL-3.0-or-later and friends. * guix/import/utils.scm (spdx-string->license): Recognise GPL-N-only and GPL-N-or-later. Likewise for LGPL and AGPL. Signed-off-by: Leo Prikler --- guix/import/utils.scm | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'guix') diff --git a/guix/import/utils.scm b/guix/import/utils.scm index d817318a91..d1b8076ddd 100644 --- a/guix/import/utils.scm +++ b/guix/import/utils.scm @@ -133,8 +133,14 @@ of the string VERSION is replaced by the symbol 'version." ;; Please update guix/licenses.scm when modifying ;; this list to avoid mismatches. (match str + ;; "GPL-N+" has been deprecated in favour of "GPL-N-or-later". + ;; "GPL-N" has been deprecated in favour of "GPL-N-only" + ;; or "GPL-N-or-later" as appropriate. Likewise for LGPL + ;; and AGPL ("AGPL-1.0" 'license:agpl1) ("AGPL-3.0" 'license:agpl3) + ("AGPL-3.0-only" 'license:agpl3) + ("AGPL-3.0-or-later" 'license:agpl3+) ("Apache-1.1" 'license:asl1.1) ("Apache-2.0" 'license:asl2.0) ("BSL-1.0" 'license:boost1.0) @@ -161,11 +167,17 @@ of the string VERSION is replaced by the symbol 'version." ("GFDL-1.3" 'license:fdl1.3+) ("Giftware" 'license:giftware) ("GPL-1.0" 'license:gpl1) + ("GPL-1.0-only" 'license:gpl1) ("GPL-1.0+" 'license:gpl1+) + ("GPL-1.0-or-later" 'license:gpl1+) ("GPL-2.0" 'license:gpl2) + ("GPL-2.0-only" 'license:gpl2) ("GPL-2.0+" 'license:gpl2+) + ("GPL-2.0-or-later" 'license:gpl2+) ("GPL-3.0" 'license:gpl3) + ("GPL-3.0-only" 'license:gpl3) ("GPL-3.0+" 'license:gpl3+) + ("GPL-3.0-or-later" 'license:gpl3+) ("ISC" 'license:isc) ("IJG" 'license:ijg) ("Imlib2" 'license:imlib2) @@ -173,11 +185,17 @@ of the string VERSION is replaced by the symbol 'version." ("IPL-1.0" 'license:ibmpl1.0) ("LAL-1.3" 'license:lal1.3) ("LGPL-2.0" 'license:lgpl2.0) + ("LGPL-2.0-only" 'license:lgpl2.0) ("LGPL-2.0+" 'license:lgpl2.0+) + ("LGPL-2.0-or-later" 'license:lgpl2.0+) ("LGPL-2.1" 'license:lgpl2.1) + ("LGPL-2.1-only" 'license:lgpl2.1) ("LGPL-2.1+" 'license:lgpl2.1+) + ("LGPL-2.1-or-later" 'license:lgpl2.1+) ("LGPL-3.0" 'license:lgpl3) + ("LGPL-3.0-only" 'license:lgpl3) ("LGPL-3.0+" 'license:lgpl3+) + ("LGPL-3.0-or-later" 'license:lgpl3+) ("MPL-1.0" 'license:mpl1.0) ("MPL-1.1" 'license:mpl1.1) ("MPL-2.0" 'license:mpl2.0) -- cgit v1.2.3 From 467e874a86dc3dd83fe10e5610823c011de6565a Mon Sep 17 00:00:00 2001 From: Maxime Devos Date: Tue, 10 Aug 2021 17:07:20 +0200 Subject: guix: Add ContentDB importer. * guix/import/contentdb.scm: New file. * guix/scripts/import/contentdb.scm: New file. * tests/contentdb.scm: New file. * Makefile.am (MODULES, SCM_TESTS): Register them. * po/guix/POTFILES.in: Likewise. * doc/guix.texi (Invoking guix import): Document it. Signed-off-by: Leo Prikler --- Makefile.am | 3 + doc/guix.texi | 32 +++ guix/import/minetest.scm | 456 +++++++++++++++++++++++++++++++++++++++ guix/scripts/import.scm | 3 +- guix/scripts/import/minetest.scm | 117 ++++++++++ po/guix/POTFILES.in | 1 + tests/minetest.scm | 355 ++++++++++++++++++++++++++++++ 7 files changed, 966 insertions(+), 1 deletion(-) create mode 100644 guix/import/minetest.scm create mode 100644 guix/scripts/import/minetest.scm create mode 100644 tests/minetest.scm (limited to 'guix') diff --git a/Makefile.am b/Makefile.am index 344b7423c5..327d3f9961 100644 --- a/Makefile.am +++ b/Makefile.am @@ -262,6 +262,7 @@ MODULES = \ guix/import/json.scm \ guix/import/kde.scm \ guix/import/launchpad.scm \ + guix/import/minetest.scm \ guix/import/opam.scm \ guix/import/print.scm \ guix/import/pypi.scm \ @@ -304,6 +305,7 @@ MODULES = \ guix/scripts/import/go.scm \ guix/scripts/import/hackage.scm \ guix/scripts/import/json.scm \ + guix/scripts/import/minetest.scm \ guix/scripts/import/opam.scm \ guix/scripts/import/pypi.scm \ guix/scripts/import/stackage.scm \ @@ -470,6 +472,7 @@ SCM_TESTS = \ tests/import-utils.scm \ tests/inferior.scm \ tests/lint.scm \ + tests/minetest.scm \ tests/modules.scm \ tests/monads.scm \ tests/nar.scm \ diff --git a/doc/guix.texi b/doc/guix.texi index d6197d3743..241a1824ec 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -11314,6 +11314,38 @@ and generate package expressions for all those packages that are not yet in Guix. @end table +@item contentdb +@cindex minetest +@cindex ContentDB +Import metadata from @uref{https://content.minetest.net, ContentDB}. +Information is taken from the JSON-formatted metadata provided through +@uref{https://content.minetest.net/help/api/, ContentDB's API} and +includes most relevant information, including dependencies. There are +some caveats, however. The license information is often incomplete. +The commit hash is sometimes missing. The descriptions are in the +Markdown format, but Guix uses Texinfo instead. Texture packs and +subgames are unsupported. + +The command below imports metadata for the Mesecons mod by Jeija: + +@example +guix import minetest Jeija/mesecons +@end example + +The author name can also be left out: + +@example +guix import minetest mesecons +@end example + +@table @code +@item --recursive +@itemx -r +Traverse the dependency graph of the given upstream package recursively +and generate package expressions for all those packages that are not yet +in Guix. +@end table + @item cpan @cindex CPAN Import metadata from @uref{https://www.metacpan.org/, MetaCPAN}. diff --git a/guix/import/minetest.scm b/guix/import/minetest.scm new file mode 100644 index 0000000000..e1f8487b75 --- /dev/null +++ b/guix/import/minetest.scm @@ -0,0 +1,456 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2021 Maxime Devos +;;; +;;; 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 . + +(define-module (guix import minetest) + #:use-module (ice-9 match) + #:use-module (ice-9 receive) + #:use-module (ice-9 threads) + #:use-module (ice-9 hash-table) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-2) + #:use-module (srfi srfi-11) + #:use-module (srfi srfi-26) + #:use-module (guix utils) + #:use-module (guix ui) + #:use-module (guix i18n) + #:use-module (guix memoization) + #:use-module (guix serialization) + #:use-module (guix import utils) + #:use-module (guix import json) + #:use-module ((gcrypt hash) #:select (open-sha256-port port-sha256)) + #:use-module (json) + #:use-module (guix base32) + #:use-module (guix git) + #:use-module (guix store) + #:export (%default-sort-key + %contentdb-api + json->package + contentdb-fetch + elaborate-contentdb-name + minetest->guix-package + minetest-recursive-import + sort-packages)) + +;; The ContentDB API is documented at +;; . + +(define %contentdb-api + (make-parameter "https://content.minetest.net/api/")) + +(define (string-or-false x) + (and (string? x) x)) + +(define (natural-or-false x) + (and (exact-integer? x) (>= x 0) x)) + +;; Descriptions on ContentDB use carriage returns, but Guix doesn't. +(define (delete-cr text) + (string-delete #\cr text)) + + + +;;; +;;; JSON mappings +;;; + +;; Minetest package. +;; +;; API endpoint: /packages/AUTHOR/NAME/ +(define-json-mapping make-package package? + json->package + (author package-author) ; string + (creation-date package-creation-date ; string + "created_at") + (downloads package-downloads) ; integer + (forums package-forums "forums" natural-or-false) + (issue-tracker package-issue-tracker "issue_tracker") ; string + (license package-license) ; string + (long-description package-long-description "long_description") ; string + (maintainers package-maintainers ; list of strings + "maintainers" vector->list) + (media-license package-media-license "media_license") ; string + (name package-name) ; string + (provides package-provides ; list of strings + "provides" vector->list) + (release package-release) ; integer + (repository package-repository "repo" string-or-false) + (score package-score) ; flonum + (screenshots package-screenshots "screenshots" vector->list) ; list of strings + (short-description package-short-description "short_description") ; string + (state package-state) ; string + (tags package-tags "tags" vector->list) ; list of strings + (thumbnail package-thumbnail) ; string + (title package-title) ; string + (type package-type) ; string + (url package-url) ; string + (website package-website "website" string-or-false)) + +(define-json-mapping make-release release? + json->release + ;; If present, a git commit identified by its hash + (commit release-commit "commit" string-or-false) + (downloads release-downloads) ; integer + (id release-id) ; integer + (max-minetest-version release-max-minetest-version string-or-false) + (min-minetest-version release-min-minetest-version string-or-false) + (release-date release-data) ; string + (title release-title) ; string + (url release-url)) ; string + +(define-json-mapping make-dependency dependency? + json->dependency + (optional? dependency-optional? "is_optional") ; bool + (name dependency-name) ; string + (packages dependency-packages "packages" vector->list)) ; list of strings + +;; A structure returned by the /api/packages/?fmt=keys endpoint +(define-json-mapping make-package-keys package-keys? + json->package-keys + (author package-keys-author) ; string + (name package-keys-name) ; string + (type package-keys-type)) ; string + +(define (package-mod? package) + "Is the ContentDB package PACKAGE a mod?" + ;; ContentDB also has ‘games’ and ‘texture packs’. + (string=? (package-type package) "mod")) + + + +;;; +;;; Manipulating names of packages +;;; +;;; There are three kind of names: +;;; +;;; * names of guix packages, e.g. minetest-basic-materials. +;;; * names of mods on ContentDB, e.g. basic_materials +;;; * a combination of author and mod name on ContentDB, e.g. VanessaE/basic_materials +;;; + +(define (%construct-full-name author name) + (string-append author "/" name)) + +(define (package-full-name package) + "Given a object, return the corresponding AUTHOR/NAME string." + (%construct-full-name (package-author package) (package-name package))) + +(define (package-keys-full-name package) + "Given a object, return the corresponding AUTHOR/NAME string." + (%construct-full-name (package-keys-author package) + (package-keys-name package))) + +(define (contentdb->package-name author/name) + "Given the AUTHOR/NAME of a package on ContentDB, return a Guix-compliant +name for the package." + ;; The author is not included, as the names of popular mods + ;; tend to be unique. + (string-append "minetest-" (snake-case (author/name->name author/name)))) + +(define (author/name->name author/name) + "Extract NAME from the AUTHOR/NAME string, or raise an error if AUTHOR/NAME +is ill-formatted." + (match (string-split author/name #\/) + ((author name) + (when (string-null? author) + (leave + (G_ "In ~a: author names must consist of at least a single character.~%") + author/name)) + (when (string-null? name) + (leave + (G_ "In ~a: mod names must consist of at least a single character.~%") + author/name)) + name) + ((too many . components) + (leave + (G_ "In ~a: author names and mod names may not contain forward slashes.~%") + author/name)) + ((name) + (if (string-null? name) + (leave (G_ "mod names may not be empty.~%")) + (leave (G_ "The name of the author is missing in ~a.~%") + author/name))))) + +(define* (elaborate-contentdb-name name #:key (sort %default-sort-key)) + "If NAME is an AUTHOR/NAME string, return it. Otherwise, try to determine +the author and return an appropriate AUTHOR/NAME string. If that fails, +raise an exception." + (if (or (string-contains name "/") (string-null? name)) + ;; Call 'author/name->name' to verify that NAME seems reasonable + ;; and raise an appropriate exception if it isn't. + (begin + (author/name->name name) + name) + (let* ((package-keys (contentdb-query-packages name #:sort sort)) + (correctly-named + (filter (lambda (package-key) + (string=? name (package-keys-name package-key))) + package-keys))) + (match correctly-named + ((one) (package-keys-full-name one)) + ((too . many) + (warning (G_ "~a is ambigious, presuming ~a (other options include: ~a)~%") + name (package-keys-full-name too) + (map package-keys-full-name many)) + (package-keys-full-name too)) + (() + (leave (G_ "No mods with name ~a were found.~%") name)))))) + + + +;;; +;;; API endpoints +;;; + +(define contentdb-fetch + (mlambda (author/name) + "Return a record for package AUTHOR/NAME, or #f on failure." + (and=> (json-fetch + (string-append (%contentdb-api) "packages/" author/name "/")) + json->package))) + +(define (contentdb-fetch-releases author/name) + "Return a list of records for package NAME by AUTHOR, or #f +on failure." + (and=> (json-fetch (string-append (%contentdb-api) "packages/" author/name + "/releases/")) + (lambda (json) + (map json->release (vector->list json))))) + +(define (latest-release author/name) + "Return the latest source release for package NAME by AUTHOR, +or #f if this package does not exist." + (and=> (contentdb-fetch-releases author/name) + car)) + +(define (contentdb-fetch-dependencies author/name) + "Return an alist of lists of records for package NAME by AUTHOR +and possibly some other packages as well, or #f on failure." + (define url (string-append (%contentdb-api) "packages/" author/name + "/dependencies/")) + (and=> (json-fetch url) + (lambda (json) + (map (match-lambda + ((key . value) + (cons key (map json->dependency (vector->list value))))) + json)))) + +(define* (contentdb-query-packages q #:key + (type "mod") + (limit 50) + (sort %default-sort-key) + (order "desc")) + "Search ContentDB for Q (a string). Sort by SORT, in ascending order +if ORDER is \"asc\" or descending order if ORDER is \"desc\". TYPE must +be \"mod\", \"game\" or \"txp\", restricting thes search results to +respectively mods, games and texture packs. Limit to at most LIMIT +results. The return value is a list of records." + ;; XXX does Guile have something for constructing (and, when necessary, + ;; escaping) query strings? + (define url (string-append (%contentdb-api) "packages/?type=" type + "&q=" q "&fmt=keys" + "&limit=" (number->string limit) + "&order=" order + "&sort=" sort)) + (let ((json (json-fetch url))) + (if json + (map json->package-keys (vector->list json)) + (leave + (G_ "The package search API doesn't exist anymore.~%"))))) + + + +;; XXX copied from (guix import elpa) +(define* (download-git-repository url ref) + "Fetch the given REF from the Git repository at URL." + (with-store store + (latest-repository-commit store url #:ref ref))) + +;; XXX adapted from (guix scripts hash) +(define (file-hash file) + "Compute the hash of FILE." + (let-values (((port get-hash) (open-sha256-port))) + (write-file file port) + (force-output port) + (get-hash))) + +(define (make-minetest-sexp author/name version repository commit + inputs home-page synopsis + description media-license license) + "Return a S-expression for the minetest package with the given author/NAME, +VERSION, REPOSITORY, COMMIT, INPUTS, HOME-PAGE, SYNOPSIS, DESCRIPTION, +MEDIA-LICENSE and LICENSE." + `(package + (name ,(contentdb->package-name author/name)) + (version ,version) + (source + (origin + (method git-fetch) + (uri (git-reference + (url ,repository) + (commit ,commit))) + (sha256 + (base32 + ;; The git commit is not always available. + ,(and commit + (bytevector->nix-base32-string + (file-hash + (download-git-repository repository + `(commit . ,commit))))))) + (file-name (git-file-name name version)))) + (build-system minetest-mod-build-system) + ,@(maybe-propagated-inputs (map contentdb->package-name inputs)) + (home-page ,home-page) + (synopsis ,(delete-cr synopsis)) + (description ,(delete-cr description)) + (license ,(if (eq? media-license license) + license + `(list ,media-license ,license))) + ;; The Minetest updater (not yet in Guix; it requires not-yet-submitted + ;; patches to (guix upstream) that require some work) needs to know both + ;; the author name and mod name for efficiency. + (properties ,(list 'quasiquote `((upstream-name . ,author/name)))))) + +(define (package-home-page package) + "Guess the home page of the ContentDB package PACKAGE. + +In order of preference, try the 'website', the forum topic on the +official Minetest forum and the Git repository (if any)." + (define (topic->url-sexp topic) + ;; 'minetest-topic' is a procedure defined in (gnu packages minetest) + `(minetest-topic ,topic)) + (or (package-website package) + (and=> (package-forums package) topic->url-sexp) + (package-repository package))) + +;; If the default sort key is changed, make sure to modify 'show-help' +;; in (guix scripts import minetest) appropriately as well. +(define %default-sort-key "score") + +(define* (sort-packages packages #:key (sort %default-sort-key)) + "Sort PACKAGES by SORT, in descending order." + (define package->key + (match sort + ("score" package-score) + ("downloads" package-downloads))) + (define (greater x y) + (> (package->key x) (package->key y))) + (sort-list packages greater)) + +(define builtin-mod? + (let ((%builtin-mods + (alist->hash-table + (map (lambda (x) (cons x #t)) + '("beds" "binoculars" "boats" "bones" "bucket" "butterflies" + "carts" "creative" "default" "doors" "dungeon_loot" "dye" + "env_sounds" "farming" "fire" "fireflies" "flowers" + "game_commands" "give_initial_stuff" "map" "mtg_craftguide" + "player_api" "screwdriver" "sethome" "sfinv" "spawn" "stairs" + "tnt" "vessels" "walls" "weather" "wool" "xpanes"))))) + (lambda (mod) + "Is MOD provided by the default minetest subgame?" + (hash-ref %builtin-mods mod)))) + +(define* (important-dependencies dependencies author/name + #:key (sort %default-sort-key)) + "Return the hard dependencies of AUTHOR/NAME in the association list +DEPENDENCIES as a list of AUTHOR/NAME strings." + (define dependency-list + (assoc-ref dependencies author/name)) + (filter-map + (lambda (dependency) + (and (not (dependency-optional? dependency)) + (not (builtin-mod? (dependency-name dependency))) + ;; The dependency information contains symbolic names + ;; that can be ‘provided’ by multiple mods, so we need to choose one + ;; of the implementations. + (let* ((implementations + (par-map contentdb-fetch (dependency-packages dependency))) + ;; Fetching package information about the packages is racy: + ;; some packages might be removed from ContentDB between the + ;; construction of DEPENDENCIES and the call to + ;; 'contentdb-fetch'. So filter out #f. + ;; + ;; Filter out ‘games’ that include the requested mod -- it's + ;; the mod itself we want. + (mods (filter (lambda (p) (and=> p package-mod?)) + implementations)) + (sorted-mods (sort-packages mods #:sort sort))) + (match sorted-mods + ((package) (package-full-name package)) + ((too . many) + (warning + (G_ "The dependency ~a of ~a has multiple different implementations ~a.~%") + (dependency-name dependency) + author/name + (map package-full-name sorted-mods)) + (match sort + ("score" + (warning + (G_ "The implementation with the highest score will be choosen!~%"))) + ("downloads" + (warning + (G_ "The implementation that has been downloaded the most will be choosen!~%")))) + (package-full-name too)) + (() + (warning + (G_ "The dependency ~a of ~a does not have any implementation. It will be ignored!~%") + (dependency-name dependency) author/name) + #f))))) + dependency-list)) + +(define* (%minetest->guix-package author/name #:key (sort %default-sort-key)) + "Fetch the metadata for AUTHOR/NAME from https://content.minetest.net, and +return the 'package' S-expression corresponding to that package, or raise an +exception on failure. On success, also return the upstream dependencies as a +list of AUTHOR/NAME strings." + ;; Call 'author/name->name' to verify that AUTHOR/NAME seems reasonable. + (author/name->name author/name) + (define package (contentdb-fetch author/name)) + (unless package + (leave (G_ "no package metadata for ~a on ContentDB~%") author/name)) + (define dependencies (contentdb-fetch-dependencies author/name)) + (unless dependencies + (leave (G_ "no dependency information for ~a on ContentDB~%") author/name)) + (define release (latest-release author/name)) + (unless release + (leave (G_ "no release of ~a on ContentDB~%") author/name)) + (define important-upstream-dependencies + (important-dependencies dependencies author/name #:sort sort)) + (values (make-minetest-sexp author/name + (release-title release) ; version + (package-repository package) + (release-commit release) + important-upstream-dependencies + (package-home-page package) + (package-short-description package) + (package-long-description package) + (spdx-string->license + (package-media-license package)) + (spdx-string->license + (package-license package))) + important-upstream-dependencies)) + +(define minetest->guix-package + (memoize %minetest->guix-package)) + +(define* (minetest-recursive-import author/name #:key (sort %default-sort-key)) + (define* (minetest->guix-package* author/name #:key repo version) + (minetest->guix-package author/name #:sort sort)) + (recursive-import author/name + #:repo->guix-package minetest->guix-package* + #:guix-name contentdb->package-name)) diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm index f53d1ac1f4..b369a362d0 100644 --- a/guix/scripts/import.scm +++ b/guix/scripts/import.scm @@ -77,7 +77,8 @@ rather than \\n." ;;; (define importers '("gnu" "pypi" "cpan" "hackage" "stackage" "egg" "elpa" - "gem" "go" "cran" "crate" "texlive" "json" "opam")) + "gem" "go" "cran" "crate" "texlive" "json" "opam" + "minetest")) (define (resolve-importer name) (let ((module (resolve-interface diff --git a/guix/scripts/import/minetest.scm b/guix/scripts/import/minetest.scm new file mode 100644 index 0000000000..5f204d90fc --- /dev/null +++ b/guix/scripts/import/minetest.scm @@ -0,0 +1,117 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2014 David Thompson +;;; Copyright © 2018 Ricardo Wurmus +;;; Copyright © 2021 Maxime Devos +;;; +;;; 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 . + +(define-module (guix scripts import minetest) + #:use-module (guix ui) + #:use-module (guix utils) + #:use-module (guix scripts) + #:use-module (guix import minetest) + #:use-module (guix import utils) + #:use-module (guix scripts import) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-11) + #:use-module (srfi srfi-37) + #:use-module (ice-9 match) + #:use-module (ice-9 format) + #:export (guix-import-minetest)) + + +;;; +;;; Command-line options. +;;; + +(define %default-options + `((sort . ,%default-sort-key))) + +(define (show-help) + (display (G_ "Usage: guix import minetest AUTHOR/NAME +Import and convert the Minetest mod NAME by AUTHOR from ContentDB.\n")) + (display (G_ " + -h, --help display this help and exit")) + (display (G_ " + -r, --recursive import packages recursively")) + (display (G_ " + -V, --version display version information and exit")) + (display (G_ " + --sort=KEY when choosing between multiple implementations, + choose the one with the highest value for KEY + (one of \"score\" (standard) or \"downloads\")")) + (newline) + (show-bug-report-information)) + +(define (verify-sort-order sort) + "Verify SORT can be used to sort mods by." + (unless (member sort '("score" "downloads" "reviews")) + (leave (G_ "~a: not a valid key to sort by~%") sort)) + sort) + +(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 minetest"))) + (option '(#\r "recursive") #f #f + (lambda (opt name arg result) + (alist-cons 'recursive #t result))) + (option '("sort") #t #f + (lambda (opt name arg result) + (alist-cons 'sort (verify-sort-order arg) result))) + %standard-import-options)) + + +;;; +;;; Entry point. +;;; + +(define (guix-import-minetest . 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 + ((name) + (with-error-handling + (let* ((sort (assoc-ref opts 'sort)) + (author/name (elaborate-contentdb-name name #:sort sort))) + (if (assoc-ref opts 'recursive) + ;; Recursive import + (filter-map package->definition + (minetest-recursive-import author/name #:sort sort)) + ;; Single import + (minetest->guix-package author/name #:sort sort))))) + (() + (leave (G_ "too few arguments~%"))) + ((many ...) + (leave (G_ "too many arguments~%")))))) diff --git a/po/guix/POTFILES.in b/po/guix/POTFILES.in index 14324b25de..1eee82be53 100644 --- a/po/guix/POTFILES.in +++ b/po/guix/POTFILES.in @@ -60,6 +60,7 @@ guix/scripts/git.scm guix/scripts/git/authenticate.scm guix/scripts/hash.scm guix/scripts/import.scm +guix/scripts/import/contentdb.scm guix/scripts/import/cran.scm guix/scripts/import/elpa.scm guix/scripts/pull.scm diff --git a/tests/minetest.scm b/tests/minetest.scm new file mode 100644 index 0000000000..6ae476fe5f --- /dev/null +++ b/tests/minetest.scm @@ -0,0 +1,355 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2021 Maxime Devos +;;; +;;; 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 . + +(define-module (test-minetest) + #:use-module (guix memoization) + #:use-module (guix import minetest) + #:use-module (guix import utils) + #:use-module (guix tests) + #:use-module (json) + #:use-module (ice-9 match) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) + #:use-module (srfi srfi-34) + #:use-module (srfi srfi-64)) + + +;; Some procedures for populating a ‘fake’ ContentDB server. + +(define* (make-package-sexp #:key + (guix-name "minetest-foo") + (home-page "https://example.org/foo") + (repo "https://example.org/foo.git") + (synopsis "synopsis") + (guix-description "description") + (guix-license + '(list license:cc-by-sa4.0 license:lgpl3+)) + (inputs '()) + (upstream-name "Author/foo") + #:allow-other-keys) + `(package + (name ,guix-name) + ;; This is not a proper version number but ContentDB does not include + ;; version numbers. + (version "2021-07-25") + (source + (origin + (method git-fetch) + (uri (git-reference + (url ,(and (not (eq? repo 'null)) repo)) + (commit #f))) + (sha256 + (base32 #f)) + (file-name (git-file-name name version)))) + (build-system minetest-mod-build-system) + ,@(maybe-propagated-inputs inputs) + (home-page ,home-page) + (synopsis ,synopsis) + (description ,guix-description) + (license ,guix-license) + (properties + ,(list 'quasiquote + `((upstream-name . ,upstream-name)))))) + +(define* (make-package-json #:key + (author "Author") + (name "foo") + (media-license "CC-BY-SA-4.0") + (license "LGPL-3.0-or-later") + (short-description "synopsis") + (long-description "description") + (repo "https://example.org/foo.git") + (website "https://example.org/foo") + (forums 321) + (score 987.654) + (downloads 123) + (type "mod") + #:allow-other-keys) + `(("author" . ,author) + ("content_warnings" . #()) + ("created_at" . "2018-05-23T19:58:07.422108") + ("downloads" . ,downloads) + ("forums" . ,forums) + ("issue_tracker" . "https://example.org/foo/issues") + ("license" . ,license) + ("long_description" . ,long-description) + ("maintainers" . #("maintainer")) + ("media_license" . ,media-license) + ("name" . ,name) + ("provides" . #("stuff")) + ("release" . 456) + ("repo" . ,repo) + ("score" . ,score) + ("screenshots" . #()) + ("short_description" . ,short-description) + ("state" . "APPROVED") + ("tags" . #("some" "tags")) + ("thumbnail" . null) + ("title" . "The name") + ("type" . ,type) + ("url" . ,(string-append "https://content.minetest.net/packages/" + author "/" name "/download/")) + ("website" . ,website))) + +(define* (make-releases-json #:key (commit #f) (title "") #:allow-other-keys) + `#((("commit" . ,commit) + ("downloads" . 469) + ("id" . 8614) + ("max_minetest_version" . null) + ("min_minetest_version" . null) + ("release_date" . "2021-07-25T01:10:23.207584") + ("title" . "2021-07-25")))) + +(define* (make-dependencies-json #:key (author "Author") + (name "foo") + (requirements '(("default" #f ()))) + #:allow-other-keys) + `((,(string-append author "/" name) + . ,(list->vector + (map (match-lambda + ((symbolic-name optional? implementations) + `(("is_optional" . ,optional?) + ("name" . ,symbolic-name) + ("packages" . ,(list->vector implementations))))) + requirements))) + ("something/else" . #()))) + +(define* (make-packages-keys-json #:key (author "Author") + (name "Name") + (type "mod")) + `(("author" . ,author) + ("name" . ,name) + ("type" . ,type))) + +(define (call-with-packages thunk . argument-lists) + ;; Don't reuse results from previous tests. + (invalidate-memoization! contentdb-fetch) + (invalidate-memoization! minetest->guix-package) + (define (scm->json-port scm) + (open-input-string (scm->json-string scm))) + (define (handle-package url requested-author requested-name . rest) + (define relevant-argument-list + (any (lambda (argument-list) + (apply (lambda* (#:key (author "Author") (name "foo") + #:allow-other-keys) + (and (equal? requested-author author) + (equal? requested-name name) + argument-list)) + argument-list)) + argument-lists)) + (when (not relevant-argument-list) + (error "the package ~a/~a should be irrelevant, but ~a is fetched" + requested-author requested-name url)) + (scm->json-port + (apply (match rest + (("") make-package-json) + (("dependencies" "") make-dependencies-json) + (("releases" "") make-releases-json) + (_ (error "TODO ~a" rest))) + relevant-argument-list))) + (define (handle-mod-search sort) + ;; Produce search results, sorted by SORT in descending order. + (define arguments->key + (match sort + ("score" (lambda* (#:key (score 987.654) #:allow-other-keys) + score)) + ("downloads" (lambda* (#:key (downloads 123) #:allow-other-keys) + downloads)))) + (define argument-list->key (cut apply arguments->key <>)) + (define (greater x y) + (> (argument-list->key x) (argument-list->key y))) + (define sorted-argument-lists (sort-list argument-lists greater)) + (define* (arguments->json #:key (author "Author") (name "Foo") (type "mod") + #:allow-other-keys) + (and (string=? type "mod") + `(("author" . ,author) + ("name" . ,name) + ("type" . ,type)))) + (define argument-list->json (cut apply arguments->json <>)) + (scm->json-port + (list->vector (filter-map argument-list->json sorted-argument-lists)))) + (mock ((guix http-client) http-fetch + (lambda* (url #:key headers) + (unless (string-prefix? "mock://api/packages/" url) + (error "the URL ~a should not be used" url)) + (define resource + (substring url (string-length "mock://api/packages/"))) + (define components (string-split resource #\/)) + (match components + ((author name . rest) + (apply handle-package url author name rest)) + (((? (cut string-prefix? "?type=mod&q=" <>) query)) + (handle-mod-search + (cond ((string-contains query "sort=score") "score") + ((string-contains query "sort=downloads") "downloads") + (#t (error "search query ~a has unknown sort key" + query))))) + (_ + (error "the URL ~a should have an author and name component" + url))))) + (parameterize ((%contentdb-api "mock://api/")) + (thunk)))) + +(define* (minetest->guix-package* #:key (author "Author") (name "foo") + (sort %default-sort-key) + #:allow-other-keys) + (minetest->guix-package (string-append author "/" name) #:sort sort)) + +(define (imported-package-sexp* primary-arguments . secondary-arguments) + "Ask the importer to import a package specified by PRIMARY-ARGUMENTS, +during a dynamic where that package and the packages specified by +SECONDARY-ARGUMENTS are available on ContentDB." + (apply call-with-packages + (lambda () + ;; The memoization cache is reset by call-with-packages + (apply minetest->guix-package* primary-arguments)) + primary-arguments + secondary-arguments)) + +(define (imported-package-sexp . extra-arguments) + "Ask the importer to import a package specified by EXTRA-ARGUMENTS, +during a dynamic extent where that package is available on ContentDB." + (imported-package-sexp* extra-arguments)) + +(define-syntax-rule (test-package test-case . extra-arguments) + (test-equal test-case + (make-package-sexp . extra-arguments) + (imported-package-sexp . extra-arguments))) + +(define-syntax-rule (test-package* test-case primary-arguments extra-arguments + ...) + (test-equal test-case + (apply make-package-sexp primary-arguments) + (imported-package-sexp* primary-arguments extra-arguments ...))) + +(test-begin "minetest") + + +;; Package names +(test-package "minetest->guix-package") +(test-package "minetest->guix-package, _ → - in package name" + #:name "foo_bar" + #:guix-name "minetest-foo-bar" + #:upstream-name "Author/foo_bar") + +(test-equal "elaborate names, unambigious" + "Jeija/mesecons" + (call-with-packages + (cut elaborate-contentdb-name "mesecons") + '(#:name "mesecons" #:author "Jeija") + '(#:name "something" #:author "else"))) + +(test-equal "elaborate name, ambigious (highest score)" + "Jeija/mesecons" + (call-with-packages + ;; #:sort "score" is the default + (cut elaborate-contentdb-name "mesecons") + '(#:name "mesecons" #:author "Jeijc" #:score 777) + '(#:name "mesecons" #:author "Jeijb" #:score 888) + '(#:name "mesecons" #:author "Jeija" #:score 999))) + + +(test-equal "elaborate name, ambigious (most downloads)" + "Jeija/mesecons" + (call-with-packages + (cut elaborate-contentdb-name "mesecons" #:sort "downloads") + '(#:name "mesecons" #:author "Jeijc" #:downloads 777) + '(#:name "mesecons" #:author "Jeijb" #:downloads 888) + '(#:name "mesecons" #:author "Jeija" #:downloads 999))) + + +;; Determining the home page +(test-package "minetest->guix-package, website is used as home page" + #:home-page "web://site" + #:website "web://site") +(test-package "minetest->guix-package, if absent, the forum is used" + #:home-page '(minetest-topic 628) + #:forums 628 + #:website 'null) +(test-package "minetest->guix-package, if absent, the git repo is used" + #:home-page "https://github.com/minetest-mods/mesecons" + #:forums 'null + #:website 'null + #:repo "https://github.com/minetest-mods/mesecons") +(test-package "minetest->guix-package, all home page information absent" + #:home-page #f + #:forums 'null + #:website 'null + #:repo 'null) + + + +;; Dependencies +(test-package* "minetest->guix-package, unambigious dependency" + (list #:requirements '(("mesecons" #f + ("Jeija/mesecons" + "some-modpack/containing-mese"))) + #:inputs '("minetest-mesecons")) + (list #:author "Jeija" #:name "mesecons") + (list #:author "some-modpack" #:name "containing-mese" #:type "modpack")) + +(test-package* "minetest->guix-package, ambigious dependency (highest score)" + (list #:name "frobnicate" + #:guix-name "minetest-frobnicate" + #:upstream-name "Author/frobnicate" + #:requirements '(("frob" #f + ("Author/foo" "Author/bar"))) + ;; #:sort "score" is the default + #:inputs '("minetest-bar")) + (list #:author "Author" #:name "foo" #:score 0) + (list #:author "Author" #:name "bar" #:score 9999)) + +(test-package* "minetest->guix-package, ambigious dependency (most downloads)" + (list #:name "frobnicate" + #:guix-name "minetest-frobnicate" + #:upstream-name "Author/frobnicate" + #:requirements '(("frob" #f + ("Author/foo" "Author/bar"))) + #:inputs '("minetest-bar") + #:sort "downloads") + (list #:author "Author" #:name "foo" #:downloads 0) + (list #:author "Author" #:name "bar" #:downloads 9999)) + +(test-package "minetest->guix-package, optional dependency" + #:requirements '(("mesecons" #t + ("Jeija/mesecons" + "some-modpack/containing-mese"))) + #:inputs '()) + + +;; License +(test-package "minetest->guix-package, identical licenses" + #:guix-license 'license:lgpl3+ + #:license "LGPL-3.0-or-later" + #:media-license "LGPL-3.0-or-later") + +;; Sorting +(let* ((make-package + (lambda arguments + (json->package (apply make-package-json arguments)))) + (x (make-package #:score 0)) + (y (make-package #:score 1)) + (z (make-package #:score 2))) + (test-equal "sort-packages, already sorted" + (list z y x) + (sort-packages (list z y x))) + (test-equal "sort-packages, reverse" + (list z y x) + (sort-packages (list x y z)))) + +(test-end "minetest") -- cgit v1.2.3 From b7d1698f7fb1f4119d29951d0059b26770e2a853 Mon Sep 17 00:00:00 2001 From: Leo Prikler Date: Fri, 20 Aug 2021 13:34:59 +0200 Subject: gnu: minetest: move to minetest.scm. * gnu/packages/games.scm (minetest, minetest-data): Move from here... * gnu/packages/minetest.scm (minetest, minetest-data): ... to here. * guix/build-system/minetest.scm (default-minetest): Adjust accordingly. --- gnu/packages/games.scm | 137 +---------------------------------- gnu/packages/minetest.scm | 161 +++++++++++++++++++++++++++++++++++++++++ guix/build-system/minetest.scm | 2 +- 3 files changed, 164 insertions(+), 136 deletions(-) (limited to 'guix') diff --git a/gnu/packages/games.scm b/gnu/packages/games.scm index fbf43b9b10..0249662d23 100644 --- a/gnu/packages/games.scm +++ b/gnu/packages/games.scm @@ -1,7 +1,7 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2013 John Darrington ;;; Copyright © 2013 Nikita Karetnikov -;;; Copyright © 2014, 2016 David Thompson +;;; Copyright © 2014, 2015 David Thompson ;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Eric Bavier ;;; Copyright © 2014 Cyrill Schenkel ;;; Copyright © 2014 Sylvain Beucler @@ -52,7 +52,7 @@ ;;; Copyright © 2020 Jack Hill ;;; Copyright © 2020 Vincent Legoll ;;; Copyright © 2020, 2021 Michael Rohleder -;;; Copyright © 2020, 2021 Trevor Hass +;;; Copyright © 2020 Trevor Hass ;;; Copyright © 2020, 2021 Leo Prikler ;;; Copyright © 2020 Lu hux ;;; Copyright © 2020 Tomás Ortín Fernández @@ -3582,139 +3582,6 @@ enemies in different game modes such as space ball, death match, team death match, cannon keep, and grave-itation pit.") (license license:gpl3+)))) -(define-public minetest - (package - (name "minetest") - (version "5.4.1") - (source (origin - (method git-fetch) - (uri (git-reference - (url "https://github.com/minetest/minetest") - (commit version))) - (file-name (git-file-name name version)) - (sha256 - (base32 - "062ilb7s377q3hwfhl8q06vvcw2raydz5ljzlzwy2dmyzmdcndb8")) - (modules '((guix build utils))) - (patches - (search-patches - "minetest-add-MINETEST_MOD_PATH.patch")) - (snippet - '(begin - ;; Delete bundled libraries. - (delete-file-recursively "lib") - #t)))) - (build-system cmake-build-system) - (arguments - `(#:configure-flags - (list "-DRUN_IN_PLACE=0" - "-DENABLE_FREETYPE=1" - "-DENABLE_GETTEXT=1" - "-DENABLE_SYSTEM_JSONCPP=TRUE" - (string-append "-DIRRLICHT_INCLUDE_DIR=" - (assoc-ref %build-inputs "irrlicht") - "/include/irrlicht") - (string-append "-DCURL_INCLUDE_DIR=" - (assoc-ref %build-inputs "curl") - "/include/curl")) - #:phases - (modify-phases %standard-phases - (add-after 'unpack 'patch-sources - (lambda* (#:key inputs #:allow-other-keys) - (substitute* "src/filesys.cpp" - ;; Use store-path for "rm" instead of non-existing FHS path. - (("\"/bin/rm\"") - (string-append "\"" (assoc-ref inputs "coreutils") "/bin/rm\""))) - (substitute* "src/CMakeLists.txt" - ;; Let minetest binary remain in build directory. - (("set\\(EXECUTABLE_OUTPUT_PATH .*\\)") "")) - (substitute* "src/unittest/test_servermodmanager.cpp" - ;; do no override MINETEST_SUBGAME_PATH - (("(un)?setenv\\(\"MINETEST_SUBGAME_PATH\".*\\);") - "(void)0;")) - (setenv "MINETEST_SUBGAME_PATH" - (string-append (getcwd) "/games")) ; for check - #t)) - (replace 'check - (lambda* (#:key tests? #:allow-other-keys) - ;; Thanks to our substitutions, the tests should also run - ;; when invoked on the target outside of `guix build'. - (when tests? - (setenv "HOME" "/tmp") - (invoke "src/minetest" "--run-unittests"))))))) - (native-search-paths - (list (search-path-specification - (variable "MINETEST_SUBGAME_PATH") - (files '("share/minetest/games"))) - (search-path-specification - (variable "MINETEST_MOD_PATH") - (files '("share/minetest/mods"))))) - (native-inputs - `(("pkg-config" ,pkg-config))) - (inputs - `(("coreutils" ,coreutils) - ("curl" ,curl) - ("freetype" ,freetype) - ("gettext" ,gettext-minimal) - ("gmp" ,gmp) - ("irrlicht" ,irrlicht) - ("jsoncpp" ,jsoncpp) - ("libjpeg" ,libjpeg-turbo) - ("libpng" ,libpng) - ("libogg" ,libogg) - ("libvorbis" ,libvorbis) - ("libxxf86vm" ,libxxf86vm) - ("luajit" ,luajit) - ("mesa" ,mesa) - ("ncurses" ,ncurses) - ("openal" ,openal) - ("sqlite" ,sqlite))) - (propagated-inputs - `(("minetest-data" ,minetest-data))) - (synopsis "Infinite-world block sandbox game") - (description - "Minetest is a sandbox construction game. Players can create and destroy -various types of blocks in a three-dimensional open world. This allows -forming structures in every possible creation, on multiplayer servers or as a -single player. Mods and texture packs allow players to personalize the game -in different ways.") - (home-page "https://www.minetest.net/") - (license license:lgpl2.1+))) - -(define minetest-data - (package - (name "minetest-data") - (version (package-version minetest)) - (source (origin - (method git-fetch) - (uri (git-reference - (url "https://github.com/minetest/minetest_game") - (commit version))) - (file-name (git-file-name name version)) - (sha256 - (base32 - "0i45lbnikvgj9kxdp0yphpjjwjcgp4ibn49xkj78j5ic1s9n8jd4")))) - (build-system trivial-build-system) - (native-inputs - `(("source" ,source))) - (arguments - `(#:modules ((guix build utils)) - #:builder (begin - (use-modules (guix build utils)) - (let ((install-dir (string-append - %output - "/share/minetest/games/minetest_game"))) - (mkdir-p install-dir) - (copy-recursively - (assoc-ref %build-inputs "source") - install-dir) - #t)))) - (synopsis "Main game data for the Minetest game engine") - (description - "Game data for the Minetest infinite-world block sandbox game.") - (home-page "https://www.minetest.net/") - (license license:lgpl2.1+))) - (define glkterm (package (name "glkterm") diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm index 0cb31808c9..5453f4d16a 100644 --- a/gnu/packages/minetest.scm +++ b/gnu/packages/minetest.scm @@ -1,3 +1,12 @@ +;;; Copyright © 2014, 2015, 2016 David Thompson +;;; Copyright © 2015 Andreas Enge +;;; Copyright © 2018 Efraim Flashner +;;; Copyright © 2015, 2019 Mark H Weaver +;;; Copyright © 2016, 2017, 2018, 2019 Kei Kebreau +;;; Copyright © 2019 Marius Bakke +;;; Copyright © 2019–2021 Tobias Geerinckx-Rice +;;; Copyright © 2021 Trevor Hass +;;; Copyright © 2020, 2021 Leo Prikler ;;; Copyright © 2021 Maxime Devos ;;; This file is part of GNU Guix. ;;; @@ -14,12 +23,164 @@ ;;; You should have received a copy of the GNU General Public License ;;; along with GNU Guix. If not, see . (define-module (gnu packages minetest) + #:use-module (gnu packages) + #:use-module (gnu packages audio) + #:use-module (gnu packages base) + #:use-module (gnu packages curl) + #:use-module (gnu packages fontutils) + #:use-module (gnu packages games) + #:use-module (gnu packages gettext) + #:use-module (gnu packages gl) + #:use-module (gnu packages image) + #:use-module (gnu packages lua) + #:use-module (gnu packages multiprecision) + #:use-module (gnu packages ncurses) + #:use-module (gnu packages pkg-config) + #:use-module (gnu packages serialization) + #:use-module (gnu packages sqlite) + #:use-module (gnu packages xiph) + #:use-module (gnu packages xorg) #:use-module (guix packages) #:use-module (guix git-download) + #:use-module (guix build-system cmake) #:use-module (guix build-system copy) + #:use-module (guix build-system trivial) #:use-module (guix build-system minetest) #:use-module ((guix licenses) #:prefix license:)) +(define-public minetest + (package + (name "minetest") + (version "5.4.1") + (source (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/minetest/minetest") + (commit version))) + (file-name (git-file-name name version)) + (sha256 + (base32 + "062ilb7s377q3hwfhl8q06vvcw2raydz5ljzlzwy2dmyzmdcndb8")) + (modules '((guix build utils))) + (patches + (search-patches + "minetest-add-MINETEST_MOD_PATH.patch")) + (snippet + '(begin + ;; Delete bundled libraries. + (delete-file-recursively "lib") + #t)))) + (build-system cmake-build-system) + (arguments + `(#:configure-flags + (list "-DRUN_IN_PLACE=0" + "-DENABLE_FREETYPE=1" + "-DENABLE_GETTEXT=1" + "-DENABLE_SYSTEM_JSONCPP=TRUE" + (string-append "-DIRRLICHT_INCLUDE_DIR=" + (assoc-ref %build-inputs "irrlicht") + "/include/irrlicht") + (string-append "-DCURL_INCLUDE_DIR=" + (assoc-ref %build-inputs "curl") + "/include/curl")) + #:phases + (modify-phases %standard-phases + (add-after 'unpack 'patch-sources + (lambda* (#:key inputs #:allow-other-keys) + (substitute* "src/filesys.cpp" + ;; Use store-path for "rm" instead of non-existing FHS path. + (("\"/bin/rm\"") + (string-append "\"" (assoc-ref inputs "coreutils") "/bin/rm\""))) + (substitute* "src/CMakeLists.txt" + ;; Let minetest binary remain in build directory. + (("set\\(EXECUTABLE_OUTPUT_PATH .*\\)") "")) + (substitute* "src/unittest/test_servermodmanager.cpp" + ;; do no override MINETEST_SUBGAME_PATH + (("(un)?setenv\\(\"MINETEST_SUBGAME_PATH\".*\\);") + "(void)0;")) + (setenv "MINETEST_SUBGAME_PATH" + (string-append (getcwd) "/games")) ; for check + #t)) + (replace 'check + (lambda* (#:key tests? #:allow-other-keys) + ;; Thanks to our substitutions, the tests should also run + ;; when invoked on the target outside of `guix build'. + (when tests? + (setenv "HOME" "/tmp") + (invoke "src/minetest" "--run-unittests"))))))) + (native-search-paths + (list (search-path-specification + (variable "MINETEST_SUBGAME_PATH") + (files '("share/minetest/games"))) + (search-path-specification + (variable "MINETEST_MOD_PATH") + (files '("share/minetest/mods"))))) + (native-inputs + `(("pkg-config" ,pkg-config))) + (inputs + `(("coreutils" ,coreutils) + ("curl" ,curl) + ("freetype" ,freetype) + ("gettext" ,gettext-minimal) + ("gmp" ,gmp) + ("irrlicht" ,irrlicht) + ("jsoncpp" ,jsoncpp) + ("libjpeg" ,libjpeg-turbo) + ("libpng" ,libpng) + ("libogg" ,libogg) + ("libvorbis" ,libvorbis) + ("libxxf86vm" ,libxxf86vm) + ("luajit" ,luajit) + ("mesa" ,mesa) + ("ncurses" ,ncurses) + ("openal" ,openal) + ("sqlite" ,sqlite))) + (propagated-inputs + `(("minetest-data" ,minetest-data))) + (synopsis "Infinite-world block sandbox game") + (description + "Minetest is a sandbox construction game. Players can create and destroy +various types of blocks in a three-dimensional open world. This allows +forming structures in every possible creation, on multiplayer servers or as a +single player. Mods and texture packs allow players to personalize the game +in different ways.") + (home-page "https://www.minetest.net/") + (license license:lgpl2.1+))) + +(define minetest-data + (package + (name "minetest-data") + (version (package-version minetest)) + (source (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/minetest/minetest_game") + (commit version))) + (file-name (git-file-name name version)) + (sha256 + (base32 + "0i45lbnikvgj9kxdp0yphpjjwjcgp4ibn49xkj78j5ic1s9n8jd4")))) + (build-system trivial-build-system) + (native-inputs + `(("source" ,source))) + (arguments + `(#:modules ((guix build utils)) + #:builder (begin + (use-modules (guix build utils)) + (let ((install-dir (string-append + %output + "/share/minetest/games/minetest_game"))) + (mkdir-p install-dir) + (copy-recursively + (assoc-ref %build-inputs "source") + install-dir) + #t)))) + (synopsis "Main game data for the Minetest game engine") + (description + "Game data for the Minetest infinite-world block sandbox game.") + (home-page "https://www.minetest.net/") + (license license:lgpl2.1+))) + (define-public (minetest-topic topic-id) "Return an URL (as a string) pointing to the forum topic with numeric identifier TOPIC-ID on the official Minetest forums." diff --git a/guix/build-system/minetest.scm b/guix/build-system/minetest.scm index f33e97559d..1fae3a47e9 100644 --- a/guix/build-system/minetest.scm +++ b/guix/build-system/minetest.scm @@ -35,7 +35,7 @@ (module-ref (resolve-interface '(gnu packages image)) 'optipng)) (define (default-minetest) - (module-ref (resolve-interface '(gnu packages games)) 'minetest)) + (module-ref (resolve-interface '(gnu packages minetest)) 'minetest)) (define (default-xvfb-run) (module-ref (resolve-interface '(gnu packages xorg)) 'xvfb-run)) -- cgit v1.2.3 From 33a1ec29fa0ad72c61cef13c8af08c847eb399c1 Mon Sep 17 00:00:00 2001 From: pukkamustard Date: Mon, 9 Aug 2021 07:19:03 +0000 Subject: guix: dune-build-system: Add a profile parameter. * guix/build-system/dune.scm: Add a profile parameter. * guix/build/dune-build-system.scm (build): Use it. * doc/guix.texi: Document it. * gnu/packages/ocaml.scm: Remove profile being set from build flags. Signed-off-by: Julien Lepiller --- doc/guix.texi | 7 +++++++ gnu/packages/ocaml.scm | 17 ++++++----------- guix/build-system/dune.scm | 3 +++ guix/build/dune-build-system.scm | 8 ++++++-- 4 files changed, 22 insertions(+), 13 deletions(-) (limited to 'guix') diff --git a/doc/guix.texi b/doc/guix.texi index 241a1824ec..949d6d4092 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -94,6 +94,7 @@ Copyright @copyright{} 2021 Xinglu Chen@* Copyright @copyright{} 2021 Raghav Gururajan@* Copyright @copyright{} 2021 Domagoj Stolfa@* Copyright @copyright{} 2021 Hui Lu@* +Copyright @copyright{} 2021 pukkamustard@* Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -7731,6 +7732,12 @@ The @code{#:package} parameter can be passed to specify a package name, which is useful when a package contains multiple packages and you want to build only one of them. This is equivalent to passing the @code{-p} argument to @code{dune}. + +The @code{#:profile} parameter can be passed to specify the +@uref{https://dune.readthedocs.io/en/stable/dune-files.html#profile, +dune build profile}. This is equivalent to passing the @code{--profile} +argument to @code{dune}. Its default value is @code{"release"}. + @end defvr @defvr {Scheme Variable} go-build-system diff --git a/gnu/packages/ocaml.scm b/gnu/packages/ocaml.scm index bdd52d2940..fee9e5e0ee 100644 --- a/gnu/packages/ocaml.scm +++ b/gnu/packages/ocaml.scm @@ -2876,8 +2876,7 @@ without a complete in-memory representation of the data.") "1dvcl108ir9nqkk4mjm9xhhj4p9dx9bmg8bnms54fizs1x3x8ar3")))) (build-system dune-build-system) (arguments - `(#:test-target "tests" - #:build-flags (list "--profile=release"))) + `(#:test-target "tests")) (propagated-inputs `(("ocaml-cmdliner" ,ocaml-cmdliner))) (home-page "https://www.typerex.org/ocp-indent.html") @@ -3295,8 +3294,7 @@ build system and allows external tools to analyse your project easily.") "1smcc0l6fh2n0y6bp96c69j5nw755jja99w0b206wx3yb2m4w2hs")))) (build-system dune-build-system) (arguments - `(#:tests? #f - #:build-flags (list "--profile" "release"))) + `(#:tests? #f)) (native-inputs `(("ocamlbuild" ,ocamlbuild))) (home-page "https://github.com/mjambon/cppo") @@ -3364,8 +3362,7 @@ standard iterator type starting from 4.07.") (base32 "07ycb103mr4mrkxfd63cwlsn023xvcjp0ra0k7n2gwrg0mwxmfss")))) (build-system dune-build-system) (arguments - `(#:tests? #f - #:build-flags (list "--profile" "release"))) + `(#:tests? #f)) (propagated-inputs `(("ocaml-seq" ,ocaml-seq))) (native-inputs @@ -3842,9 +3839,8 @@ the plugins facilitate extensibility, and the frontends serve as entry points.") "0chn7ldqb3wyf95yhmsxxq65cif56smgz1mhhc7m0dpwmyq1k97h")))) (build-system dune-build-system) (arguments - `(#:build-flags (list "--profile" "release") - #:test-target "camomile-test" - #:tests? #f; Tests fail, see https://github.com/yoriyuki/Camomile/issues/82 + `(#:test-target "camomile-test" + #:tests? #f ; Tests fail, see https://github.com/yoriyuki/Camomile/issues/82 #:phases (modify-phases %standard-phases (add-before 'build 'fix-usr-share @@ -3935,8 +3931,7 @@ connect an engine to your inputs and rendering functions to get an editor.") (base32 "0zcjy6fvf0d3i2ssz96asl889n3r6bplyzk7xvb2s3dkxbgcisyy")))) (build-system dune-build-system) (arguments - `(#:build-flags (list "--profile" "release") - #:tests? #f + `(#:tests? #f #:ocaml ,ocaml-4.07 #:findlib ,ocaml4.07-findlib #:dune ,ocaml4.07-dune)) diff --git a/guix/build-system/dune.scm b/guix/build-system/dune.scm index 6a2f3d16de..1a64cf9b75 100644 --- a/guix/build-system/dune.scm +++ b/guix/build-system/dune.scm @@ -1,6 +1,7 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2016, 2017, 2018 Julien Lepiller ;;; Copyright © 2017 Ben Woodcroft +;;; Copyright © 2021 pukkamustard ;;; ;;; This file is part of GNU Guix. ;;; @@ -88,6 +89,7 @@ (out-of-source? #t) (jbuild? #f) (package #f) + (profile "release") (tests? #t) (test-flags ''()) (test-target "test") @@ -127,6 +129,7 @@ provides a 'setup.ml' file as its build system." #:out-of-source? ,out-of-source? #:jbuild? ,jbuild? #:package ,package + #:profile ,profile #:tests? ,tests? #:test-target ,test-target #:install-target ,install-target diff --git a/guix/build/dune-build-system.scm b/guix/build/dune-build-system.scm index 7e2ec1e3e1..6a0c2593ac 100644 --- a/guix/build/dune-build-system.scm +++ b/guix/build/dune-build-system.scm @@ -1,6 +1,7 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2018 Julien Lepiller ;;; Copyright © 2019 Gabriel Hondet +;;; Copyright © 2021 pukkamustard ;;; ;;; This file is part of GNU Guix. ;;; @@ -31,11 +32,14 @@ ;; Code: (define* (build #:key (build-flags '()) (jbuild? #f) - (use-make? #f) (package #f) #:allow-other-keys) + (use-make? #f) (package #f) + (profile "release") #:allow-other-keys) "Build the given package." (let ((program (if jbuild? "jbuilder" "dune"))) (apply invoke program "build" "@install" - (append (if package (list "-p" package) '()) build-flags))) + (append (if package (list "-p" package) '()) + `("--profile" ,profile) + build-flags))) #t) (define* (check #:key (test-flags '()) (test-target "test") tests? -- cgit v1.2.3 From fc29c80b9635ff490bcc768c774442043cb1e231 Mon Sep 17 00:00:00 2001 From: Alice BRENON Date: Sat, 7 Aug 2021 19:50:10 +0200 Subject: guix: opam: More flexibility in the importer. * guix/scripts/import/opam.scm: Pass all instances of --repo as a list to the importer. * guix/import/opam.scm (opam-fetch): Stop expecting "expanded" repositories and call get-opam-repository instead to keep values "symbolic" as long as possible and factorize. (get-opam-repository): Use the same repository source as CLI opam does (i.e. HTTP-served index.tar.gz instead of git repositories). (find-latest-version): Be more flexible on the repositories structure instead of expecting packages/PACKAGE-NAME/PACKAGE-NAME.VERSION/. * tests/opam.scm: Update the call to opam->guix-package since repo is now expected to be a list and remove the mocked get-opam-repository deprecated by the support for local folders by the actual implementation. * doc/guix.texi: Document the new semantics and valid arguments for the --repo option. Signed-off-by: Julien Lepiller --- doc/guix.texi | 29 ++++++-- guix/import/opam.scm | 158 ++++++++++++++++++++++++++----------------- guix/scripts/import/opam.scm | 8 ++- tests/opam.scm | 68 +++++++++---------- 4 files changed, 159 insertions(+), 104 deletions(-) (limited to 'guix') diff --git a/doc/guix.texi b/doc/guix.texi index 949d6d4092..5155e67481 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -95,6 +95,7 @@ Copyright @copyright{} 2021 Raghav Gururajan@* Copyright @copyright{} 2021 Domagoj Stolfa@* Copyright @copyright{} 2021 Hui Lu@* Copyright @copyright{} 2021 pukkamustard@* +Copyright @copyright{} 2021 Alice Brenon@* Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -11659,14 +11660,30 @@ Traverse the dependency graph of the given upstream package recursively and generate package expressions for all those packages that are not yet in Guix. @item --repo -Select the given repository (a repository name). Possible values include: +By default, packages are searched in the official OPAM repository. This +option, which can be used more than once, lets you add other repositories +which will be searched for packages. It accepts as valid arguments: + @itemize -@item @code{opam}, the default opam repository, -@item @code{coq} or @code{coq-released}, the stable repository for coq packages, -@item @code{coq-core-dev}, the repository that contains development versions of coq, -@item @code{coq-extra-dev}, the repository that contains development versions - of coq packages. +@item the name of a known repository - can be one of @code{opam}, + @code{coq} (equivalent to @code{coq-released}), + @code{coq-core-dev}, @code{coq-extra-dev} or @code{grew}. +@item the URL of a repository as expected by the @code{opam repository + add} command (for instance, the URL equivalent of the above + @code{opam} name would be @uref{https://opam.ocaml.org}). +@item the path to a local copy of a repository (a directory containing a + @file{packages/} sub-directory). @end itemize + +Repositories are assumed to be passed to this option by order of +preference. The additional repositories will not replace the default +@code{opam} repository, which is always kept as a fallback. + +Also, please note that versions are not compared accross repositories. +The first repository (from left to right) that has at least one version +of a given package will prevail over any others, and the version +imported will be the latest one found @emph{in this repository only}. + @end table @item go diff --git a/guix/import/opam.scm b/guix/import/opam.scm index a35b01d277..fe13d29f03 100644 --- a/guix/import/opam.scm +++ b/guix/import/opam.scm @@ -2,6 +2,7 @@ ;;; Copyright © 2018 Julien Lepiller ;;; Copyright © 2020 Martin Becze ;;; Copyright © 2021 Xinglu Chen +;;; Copyright © 2021 Alice Brenon ;;; ;;; This file is part of GNU Guix. ;;; @@ -22,21 +23,24 @@ #:use-module (ice-9 ftw) #:use-module (ice-9 match) #:use-module (ice-9 peg) + #:use-module ((ice-9 popen) #:select (open-pipe*)) #:use-module (ice-9 receive) - #:use-module ((ice-9 rdelim) #:select (read-line)) #:use-module (ice-9 textual-ports) #:use-module (ice-9 vlist) #:use-module (srfi srfi-1) #:use-module (srfi srfi-2) - #:use-module (web uri) + #:use-module ((srfi srfi-26) #:select (cut)) + #:use-module ((web uri) #:select (string->uri uri->string)) + #:use-module ((guix build utils) #:select (dump-port find-files mkdir-p)) #:use-module (guix build-system) #:use-module (guix build-system ocaml) #:use-module (guix http-client) - #:use-module (guix git) #:use-module (guix ui) #:use-module (guix packages) #:use-module (guix upstream) - #:use-module (guix utils) + #:use-module ((guix utils) #:select (cache-directory + version>? + call-with-temporary-output-file)) #:use-module (guix import utils) #:use-module ((guix licenses) #:prefix license:) #:export (opam->guix-package @@ -121,51 +125,83 @@ (define-peg-pattern condition-string all (and QUOTE (* STRCHR) QUOTE)) (define-peg-pattern condition-var all (+ (or (range #\a #\z) "-" ":"))) -(define* (get-opam-repository #:optional repo) +(define (opam-cache-directory path) + (string-append (cache-directory) "/opam/" path)) + +(define known-repositories + '((opam . "https://opam.ocaml.org") + (coq . "https://coq.inria.fr/opam/released") + (coq-released . "https://coq.inria.fr/opam/released") + (coq-core-dev . "https://coq.inria.fr/opam/core-dev") + (coq-extra-dev . "https://coq.inria.fr/opam/extra-dev") + (grew . "http://opam.grew.fr"))) + +(define (get-uri repo-root) + (let ((archive-file (string-append repo-root "/index.tar.gz"))) + (or (string->uri archive-file) + (begin + (warning (G_ "'~a' is not a valid URI~%") archive-file) + 'bad-repo)))) + +(define (repo-type repo) + (match (assoc-ref known-repositories (string->symbol repo)) + (#f (if (file-exists? repo) + `(local ,repo) + `(remote ,(get-uri repo)))) + (url `(remote ,(get-uri url))))) + +(define (update-repository input) + "Make sure the cache for opam repository INPUT is up-to-date" + (let* ((output (opam-cache-directory (basename (port-filename input)))) + (cached-date (if (file-exists? output) + (stat:mtime (stat output)) + (begin (mkdir-p output) 0)))) + (when (> (stat:mtime (stat input)) cached-date) + (call-with-port + (open-pipe* OPEN_WRITE "tar" "xz" "-C" output "-f" "-") + (cut dump-port input <>))) + output)) + +(define* (get-opam-repository #:optional (repo "opam")) "Update or fetch the latest version of the opam repository and return the path to the repository." - (let ((url (cond - ((or (not repo) (equal? repo 'opam)) - "https://github.com/ocaml/opam-repository") - ((string-prefix? "coq-" (symbol->string repo)) - "https://github.com/coq/opam-coq-archive") - ((equal? repo 'coq) "https://github.com/coq/opam-coq-archive") - (else (throw 'unknown-repository repo))))) - (receive (location commit _) - (update-cached-checkout url) - (cond - ((or (not repo) (equal? repo 'opam)) - location) - ((equal? repo 'coq) - (string-append location "/released")) - ((string-prefix? "coq-" (symbol->string repo)) - (string-append location "/" (substring (symbol->string repo) 4))) - (else location))))) + (match (repo-type repo) + (('local p) p) + (('remote 'bad-repo) #f) ; to weed it out during filter-map in opam-fetch + (('remote r) (call-with-port (http-fetch/cached r) update-repository)))) ;; Prevent Guile 3 from inlining this procedure so we can mock it in tests. (set! get-opam-repository get-opam-repository) -(define (latest-version versions) - "Find the most recent version from a list of versions." - (fold (lambda (a b) (if (version>? a b) a b)) (car versions) versions)) +(define (get-version-and-file path) + "Analyse a candidate path and return an list containing information for proper + version comparison as well as the source path for metadata." + (and-let* ((metadata-file (string-append path "/opam")) + (filename (basename path)) + (version (string-join (cdr (string-split filename #\.)) "."))) + (and (file-exists? metadata-file) + (eq? 'regular (stat:type (stat metadata-file))) + (if (string-prefix? "v" version) + `(V ,(substring version 1) ,metadata-file) + `(digits ,version ,metadata-file))))) + +(define (keep-max-version a b) + "Version comparison on the lists returned by the previous function taking the + janestreet re-versioning into account (v-prefixed come first)." + (match (cons a b) + ((('V va _) . ('V vb _)) (if (version>? va vb) a b)) + ((('V _ _) . _) a) + ((_ . ('V _ _)) b) + ((('digits va _) . ('digits vb _)) (if (version>? va vb) a b)))) (define (find-latest-version package repository) "Get the latest version of a package as described in the given repository." - (let* ((dir (string-append repository "/packages/" package)) - (versions (scandir dir (lambda (name) (not (string-prefix? "." name)))))) - (if versions - (let ((versions (map - (lambda (dir) - (string-join (cdr (string-split dir #\.)) ".")) - versions))) - ;; Workaround for janestreet re-versionning - (let ((v-versions (filter (lambda (version) (string-prefix? "v" version)) versions))) - (if (null? v-versions) - (latest-version versions) - (string-append "v" (latest-version (map (lambda (version) (substring version 1)) v-versions)))))) - (begin - (format #t (G_ "Package not found in opam repository: ~a~%") package) - #f)))) + (let ((packages (string-append repository "/packages")) + (filter (make-regexp (string-append "^" package "\\.")))) + (reduce keep-max-version #f + (filter-map + get-version-and-file + (find-files packages filter #:directories? #t))))) (define (get-metadata opam-file) (with-input-from-file opam-file @@ -266,28 +302,30 @@ path to the repository." (define (depends->native-inputs depends) (filter (lambda (name) (not (equal? "" name))) - (map dependency->native-input depends))) + (map dependency->native-input depends))) (define (dependency-list->inputs lst) (map - (lambda (dependency) - (list dependency (list 'unquote (string->symbol dependency)))) - (ocaml-names->guix-names lst))) - -(define* (opam-fetch name #:optional (repository (get-opam-repository))) - (and-let* ((repository repository) - (version (find-latest-version name repository)) - (file (string-append repository "/packages/" name "/" name "." version "/opam"))) - `(("metadata" ,@(get-metadata file)) - ("version" . ,(if (string-prefix? "v" version) - (substring version 1) - version))))) - -(define* (opam->guix-package name #:key (repo 'opam) version) - "Import OPAM package NAME from REPOSITORY (a directory name) or, if -REPOSITORY is #f, from the official OPAM repository. Return a 'package' sexp + (lambda (dependency) + (list dependency (list 'unquote (string->symbol dependency)))) + (ocaml-names->guix-names lst))) + +(define* (opam-fetch name #:optional (repositories-specs '("opam"))) + (or (fold (lambda (repository others) + (match (find-latest-version name repository) + ((_ version file) `(("metadata" ,@(get-metadata file)) + ("version" . ,version))) + (_ others))) + #f + (filter-map get-opam-repository repositories-specs)) + (leave (G_ "package '~a' not found~%") name))) + +(define* (opam->guix-package name #:key (repo '()) version) + "Import OPAM package NAME from REPOSITORIES (a list of names, URLs or local +paths, always including OPAM's official repository). Return a 'package' sexp or #f on failure." - (and-let* ((opam-file (opam-fetch name (get-opam-repository repo))) + (and-let* ((with-opam (if (member "opam" repo) repo (cons "opam" repo))) + (opam-file (opam-fetch name with-opam)) (version (assoc-ref opam-file "version")) (opam-content (assoc-ref opam-file "metadata")) (url-dict (metadata-ref opam-content "url")) @@ -312,9 +350,7 @@ or #f on failure." (values `(package (name ,(ocaml-name->guix-name name)) - (version ,(if (string-prefix? "v" version) - (substring version 1) - version)) + (version ,version) (source (origin (method url-fetch) diff --git a/guix/scripts/import/opam.scm b/guix/scripts/import/opam.scm index 64164e7cc4..834ac34cb0 100644 --- a/guix/scripts/import/opam.scm +++ b/guix/scripts/import/opam.scm @@ -1,6 +1,7 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2018 Julien Lepiller ;;; Copyright © 2021 Sarah Morgensen +;;; Copyright © 2021 Alice Brenon ;;; ;;; This file is part of GNU Guix. ;;; @@ -46,7 +47,8 @@ Import and convert the opam package for PACKAGE-NAME.\n")) (display (G_ " -r, --recursive import packages recursively")) (display (G_ " - --repo import packages from this opam repository")) + --repo import packages from this opam repository (name, URL or local path) + can be used more than once")) (display (G_ " -V, --version display version information and exit")) (newline) @@ -81,7 +83,9 @@ Import and convert the opam package for PACKAGE-NAME.\n")) #:build-options? #f)) (let* ((opts (parse-options)) - (repo (and=> (assoc-ref opts 'repo) string->symbol)) + (repo (filter-map (match-lambda + (('repo . name) name) + (_ #f)) opts)) (args (filter-map (match-lambda (('argument . value) value) diff --git a/tests/opam.scm b/tests/opam.scm index f1e3b70cb0..1536b74339 100644 --- a/tests/opam.scm +++ b/tests/opam.scm @@ -82,41 +82,39 @@ url { (set! test-source-hash (call-with-input-file file-name port-sha256)))) (_ (error "Unexpected URL: " url))))) - (mock ((guix import opam) get-opam-repository - (const test-repo)) - (let ((my-package (string-append test-repo - "/packages/foo/foo.1.0.0"))) - (mkdir-p my-package) - (with-output-to-file (string-append my-package "/opam") - (lambda _ - (format #t "~a" test-opam-file)))) - (match (opam->guix-package "foo" #:repo test-repo) - (('package - ('name "ocaml-foo") - ('version "1.0.0") - ('source ('origin - ('method 'url-fetch) - ('uri "https://example.org/foo-1.0.0.tar.gz") - ('sha256 - ('base32 - (? string? hash))))) - ('build-system 'ocaml-build-system) - ('propagated-inputs - ('quasiquote - (("ocaml-zarith" ('unquote 'ocaml-zarith))))) - ('native-inputs - ('quasiquote - (("ocaml-alcotest" ('unquote 'ocaml-alcotest)) - ("ocamlbuild" ('unquote 'ocamlbuild))))) - ('home-page "https://example.org/") - ('synopsis "Some example package") - ('description "This package is just an example.") - ('license 'license:bsd-3)) - (string=? (bytevector->nix-base32-string - test-source-hash) - hash)) - (x - (pk 'fail x #f)))))) + (let ((my-package (string-append test-repo + "/packages/foo/foo.1.0.0"))) + (mkdir-p my-package) + (with-output-to-file (string-append my-package "/opam") + (lambda _ + (format #t "~a" test-opam-file)))) + (match (opam->guix-package "foo" #:repo (list test-repo)) + (('package + ('name "ocaml-foo") + ('version "1.0.0") + ('source ('origin + ('method 'url-fetch) + ('uri "https://example.org/foo-1.0.0.tar.gz") + ('sha256 + ('base32 + (? string? hash))))) + ('build-system 'ocaml-build-system) + ('propagated-inputs + ('quasiquote + (("ocaml-zarith" ('unquote 'ocaml-zarith))))) + ('native-inputs + ('quasiquote + (("ocaml-alcotest" ('unquote 'ocaml-alcotest)) + ("ocamlbuild" ('unquote 'ocamlbuild))))) + ('home-page "https://example.org/") + ('synopsis "Some example package") + ('description "This package is just an example.") + ('license 'license:bsd-3)) + (string=? (bytevector->nix-base32-string + test-source-hash) + hash)) + (x + (pk 'fail x #f))))) ;; Test the opam file parser ;; We fold over some test cases. Each case is a pair of the string to parse and the -- cgit v1.2.3 From bb5f395a08deacb799ef1e085863ba01a5f05e70 Mon Sep 17 00:00:00 2001 From: Mathieu Othacehe Date: Sun, 22 Aug 2021 21:36:29 +0200 Subject: ci: Add jobs history support. * guix/ci.scm (history?, history-evaluation, history-checkouts, history-jobs, jobs-history): New procedures. (): New record. --- guix/ci.scm | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) (limited to 'guix') diff --git a/guix/ci.scm b/guix/ci.scm index 6a3af8b42c..01b493b3af 100644 --- a/guix/ci.scm +++ b/guix/ci.scm @@ -59,6 +59,11 @@ job-status job-name + history? + history-evaluation + history-checkouts + history-jobs + %query-limit queued-builds latest-builds @@ -66,6 +71,7 @@ evaluation-jobs build job-build + jobs-history latest-evaluations evaluations-for-commit @@ -127,6 +133,18 @@ integer->build-status) (name job-name)) ;string +(define-json-mapping make-history history? + json->history + (evaluation history-evaluation) ;integer + (checkouts history-checkouts "checkouts" ;* + (lambda (checkouts) + (map json->checkout + (vector->list checkouts)))) + (jobs history-jobs "jobs" + (lambda (jobs) + (map json->job + (vector->list jobs))))) + (define-json-mapping make-checkout checkout? json->checkout (commit checkout-commit) ;string (SHA1) @@ -247,8 +265,20 @@ found (404)." "Return the build associated with JOB." (build url (job-build-id job))) -;; TODO: job history: -;; https://ci.guix.gnu.org/api/jobs/history?spec=master&names=coreutils.x86_64-linux&nr=10 +(define* (jobs-history url jobs + #:key + (specification "master") + (limit 20)) + "Return the job history for the SPECIFICATION jobs which names are part of +the JOBS list, from the CI server at URL. Limit the history to the latest +LIMIT evaluations. " + (let ((names (string-join jobs ","))) + (map json->history + (vector->list + (json->scm + (http-fetch + (format #f "~a/api/jobs/history?spec=~a&names=~a&nr=~a" + url specification names (number->string limit)))))))) (define (find-latest-commit-with-substitutes url) "Return the latest commit with available substitutes for the Guix package -- cgit v1.2.3 From 2ca982ff41270288913ad6b7d5d9e1cad87b06d9 Mon Sep 17 00:00:00 2001 From: Maxim Cournoyer Date: Fri, 6 Aug 2021 16:33:02 -0400 Subject: gnu: bootloader: Support multiple targets. Fixes . * gnu/bootloader.scm (): New 'targets' field. (%bootloader-configuration-target): New procedure. (bootloader-configuration-target): Add deprecation warning. (bootloader-configuration-targets): New procedure. * guix/scripts/system.scm (install): Access targets via bootloader-configuration-targets. (perform-action)[bootloader-target]: Remove unused argument and update doc. Access targets via bootloader-configuration-targets and fix indentation. (process-action): Access targets via bootloader-configuration-targets. Do not provide the unused BOOTLOADER-TARGET argument when applying `perform-action'. * guix/scripts/system/reconfigure.scm (install-bootloader-program): Rename DEVICE argument to DEVICES. Adjust doc and comment. Apply `installer' and `disk-installer' for every DEVICES. (install-bootloader): Access targets via bootloader-configuration-targets and rename variable from DEVICE to DEVICES. * gnu/tests/install.scm: Adjust accordingly. * tests/guix-system.sh: Likewise. * gnu/tests/reconfigure.scm (run-install-bootloader-test): Adjust the DEVICES argument so that it is a list. * doc/guix.texi: Update doc. --- doc/guix.texi | 91 +++++++++++++++++++------------------ gnu/bootloader.scm | 22 ++++++++- gnu/tests/install.scm | 26 +++++------ gnu/tests/reconfigure.scm | 2 +- guix/scripts/system.scm | 20 ++++---- guix/scripts/system/reconfigure.scm | 22 +++++---- tests/guix-system.sh | 6 +-- 7 files changed, 108 insertions(+), 81 deletions(-) (limited to 'guix') diff --git a/doc/guix.texi b/doc/guix.texi index 2b8448c856..6620f882f5 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -2569,14 +2569,15 @@ in particular: @itemize @item -Make sure the @code{bootloader-configuration} form refers to the target -you want to install GRUB on. It should mention @code{grub-bootloader} if -you are installing GRUB in the legacy way, or @code{grub-efi-bootloader} -for newer UEFI systems. For legacy systems, the @code{target} field -names a device, like @code{/dev/sda}; for UEFI systems it names a path -to a mounted EFI partition, like @code{/boot/efi}; do make sure the path is -currently mounted and a @code{file-system} entry is specified in your -configuration. +Make sure the @code{bootloader-configuration} form refers to the targets +you want to install GRUB on. It should mention @code{grub-bootloader} +if you are installing GRUB in the legacy way, or +@code{grub-efi-bootloader} for newer UEFI systems. For legacy systems, +the @code{targets} field contain the names of the devices, like +@code{(list "/dev/sda")}; for UEFI systems it names the paths to mounted +EFI partitions, like @code{(list "/boot/efi")}; do make sure the paths +are currently mounted and a @code{file-system} entry is specified in +your configuration. @item Be sure that your file system labels match the value of their respective @@ -13543,7 +13544,7 @@ the @code{bootloader} field should contain something along these lines: @lisp (bootloader-configuration (bootloader grub-efi-bootloader) - (target "/boot/efi")) + (targets '("/boot/efi"))) @end lisp @xref{Bootloader Configuration}, for more information on the available @@ -14758,7 +14759,7 @@ configuration would look like: (keyboard-layout (keyboard-layout "tr")) ;for the console (bootloader (bootloader-configuration (bootloader grub-efi-bootloader) - (target "/boot/efi") + (targets '("/boot/efi")) (keyboard-layout keyboard-layout))) ;for GRUB (services (cons (set-xorg-configuration (xorg-configuration ;for Xorg @@ -33188,11 +33189,11 @@ in ``legacy'' BIOS mode. through TFTP@. In combination with an NFS root file system this allows you to build a diskless Guix system. -The installation of the @code{grub-efi-netboot-bootloader} generates the content -of the TFTP root directory at @code{target} -(@pxref{Bootloader Configuration, @code{target}}), to be served by a TFTP server. - You may want to mount your TFTP server directory onto @code{target} to move the -required files to the TFTP server automatically. +The installation of the @code{grub-efi-netboot-bootloader} generates the +content of the TFTP root directory at @code{targets} (@pxref{Bootloader +Configuration, @code{targets}}), to be served by a TFTP server. You may +want to mount your TFTP server directories onto the @code{targets} to +move the required files to the TFTP server automatically. If you plan to use an NFS root file system as well (actually if you mount the store from an NFS share), then the TFTP server needs to serve the file @@ -33203,22 +33204,25 @@ files from the store will be accessed by GRUB through TFTP with their normal store path, for example as @file{tftp://tftp-server/gnu/store/…-initrd/initrd.cpio.gz}. -Two symlinks are created to make this possible. The first symlink is -@code{target}@file{/efi/Guix/boot/grub/grub.cfg} pointing to -@file{../../../boot/grub/grub.cfg}, -where @code{target} may be @file{/boot}. In this case the link is not leaving -the served TFTP root directory, but otherwise it does. The second link is -@code{target}@file{/gnu/store} and points to @file{../gnu/store}. This link -is leaving the served TFTP root directory. - -The assumption behind all this is that you have an NFS server exporting the root -file system for your Guix system, and additionally a TFTP server exporting your -@code{target} directory—usually @file{/boot}—from that same root file system for -your Guix system. In this constellation the symlinks will work. - -For other constellations you will have to program your own bootloader installer, -which then takes care to make necessary files from the store accessible through -TFTP, for example by copying them into the TFTP root directory at @code{target}. +Two symlinks are created to make this possible. For each target in the +@code{targets} field, the first symlink is +@samp{target}@file{/efi/Guix/boot/grub/grub.cfg} pointing to +@file{../../../boot/grub/grub.cfg}, where @samp{target} may be +@file{/boot}. In this case the link is not leaving the served TFTP root +directory, but otherwise it does. The second link is +@samp{target}@file{/gnu/store} and points to @file{../gnu/store}. This +link is leaving the served TFTP root directory. + +The assumption behind all this is that you have an NFS server exporting +the root file system for your Guix system, and additionally a TFTP +server exporting your @code{targets} directories—usually a single +@file{/boot}—from that same root file system for your Guix system. In +this constellation the symlinks will work. + +For other constellations you will have to program your own bootloader +installer, which then takes care to make necessary files from the store +accessible through TFTP, for example by copying them into the TFTP root +directory to your @code{targets}. It is important to note that symlinks pointing outside the TFTP root directory may need to be allowed in the configuration of your TFTP server. Further the @@ -33230,18 +33234,19 @@ NFS servers, you also need a properly configured DHCP server to make the booting over netboot possible. For all this we can currently only recommend you to look for instructions about @acronym{PXE, Preboot eXecution Environment}. -@item @code{target} -This is a string denoting the target onto which to install the +@item @code{targets} +This is a list of strings denoting the targets onto which to install the bootloader. -The interpretation depends on the bootloader in question. For -@code{grub-bootloader}, for example, it should be a device name understood by -the bootloader @command{installer} command, such as @code{/dev/sda} or -@code{(hd0)} (@pxref{Invoking grub-install,,, grub, GNU GRUB Manual}). For -@code{grub-efi-bootloader}, it should be the mount point of the EFI file -system, usually @file{/boot/efi}. For @code{grub-efi-netboot-bootloader}, -@code{target} should be the mount point corresponding to the TFTP root -directory of your TFTP server. +The interpretation of targets depends on the bootloader in question. +For @code{grub-bootloader}, for example, they should be device names +understood by the bootloader @command{installer} command, such as +@code{/dev/sda} or @code{(hd0)} (@pxref{Invoking grub-install,,, grub, +GNU GRUB Manual}). For @code{grub-efi-bootloader}, they should be mount +points of the EFI file system, usually @file{/boot/efi}. For +@code{grub-efi-netboot-bootloader}, @code{targets} should be the mount +points corresponding to TFTP root directories served by your TFTP +server. @item @code{menu-entries} (default: @code{()}) A possibly empty list of @code{menu-entry} objects (see below), denoting @@ -33657,7 +33662,7 @@ files, packages, and so on. It also creates other essential files needed for the system to operate correctly---e.g., the @file{/etc}, @file{/var}, and @file{/run} directories, and the @file{/bin/sh} file. -This command also installs bootloader on the target specified in +This command also installs bootloader on the targets specified in @file{my-os-config}, unless the @option{--no-bootloader} option was passed. @@ -34053,7 +34058,7 @@ evaluates to. As an example, @var{file} might contain a definition like this: (timezone "Etc/UTC") (bootloader (bootloader-configuration (bootloader grub-bootloader) - (target "/dev/vda") + (targets '("/dev/vda")) (terminal-outputs '(console)))) (file-systems (cons (file-system (mount-point "/") diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm index 6d7352ddd2..98807a4810 100644 --- a/gnu/bootloader.scm +++ b/gnu/bootloader.scm @@ -55,7 +55,8 @@ bootloader-configuration bootloader-configuration? bootloader-configuration-bootloader - bootloader-configuration-target + bootloader-configuration-target ;deprecated + bootloader-configuration-targets bootloader-configuration-menu-entries bootloader-configuration-default-entry bootloader-configuration-timeout @@ -183,7 +184,9 @@ record." bootloader-configuration make-bootloader-configuration bootloader-configuration? (bootloader bootloader-configuration-bootloader) ; - (target bootloader-configuration-target ;string + (targets %bootloader-configuration-targets ;list of strings + (default #f)) + (target %bootloader-configuration-target ;deprecated (default #f)) (menu-entries bootloader-configuration-menu-entries ;list of (default '())) @@ -204,6 +207,21 @@ record." (serial-speed bootloader-configuration-serial-speed ;integer | #f (default #f))) +;;; Deprecated. +(define (bootloader-configuration-target config) + (warning (G_ "the 'target' field is deprecated, please use 'targets' \ +instead~%")) + (%bootloader-configuration-target config)) + +(define (bootloader-configuration-targets config) + (or (%bootloader-configuration-targets config) + ;; TODO: Remove after the deprecated 'target' field is removed. + (list (bootloader-configuration-target config)) + ;; XXX: At least the GRUB installer (see (gnu bootloader grub)) has this + ;; peculiar behavior of installing fonts and GRUB modules when DEVICE is #f, + ;; hence the default value of '(#f) rather than '(). + (list #f))) + ;;; ;;; Bootloaders. diff --git a/gnu/tests/install.scm b/gnu/tests/install.scm index 80604361e0..d7fafd210c 100644 --- a/gnu/tests/install.scm +++ b/gnu/tests/install.scm @@ -4,7 +4,7 @@ ;;; Copyright © 2020 Mathieu Othacehe ;;; Copyright © 2020 Danny Milosavljevic ;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen -;;; Copyright © 2020 Maxim Cournoyer +;;; Copyright © 2020, 2021 Maxim Cournoyer ;;; ;;; This file is part of GNU Guix. ;;; @@ -97,7 +97,7 @@ (bootloader (bootloader-configuration (bootloader grub-bootloader) - (target "/dev/vdb"))) + (targets (list "/dev/vdb")))) (kernel-arguments '("console=ttyS0")) (file-systems (cons (file-system (device (file-system-label "my-root")) @@ -135,7 +135,7 @@ (bootloader (bootloader-configuration (bootloader extlinux-bootloader-gpt) - (target "/dev/vdb"))) + (targets (list "/dev/vdb")))) (kernel-arguments '("console=ttyS0")) (file-systems (cons (file-system (device (file-system-label "my-root")) @@ -418,7 +418,7 @@ per %test-installed-os, this test is expensive in terms of CPU and storage.") (bootloader (bootloader-configuration (bootloader grub-bootloader) - (target "/dev/vda"))) + (targets (list "/dev/vda")))) (kernel-arguments '("console=ttyS0")) (file-systems (cons (file-system (device (file-system-label "my-root")) @@ -549,7 +549,7 @@ partition. In particular, home directories must be correctly created (see (bootloader (bootloader-configuration (bootloader grub-bootloader) - (target "/dev/vdb"))) + (targets (list "/dev/vdb")))) (kernel-arguments '("console=ttyS0")) (file-systems (cons* (file-system (device (file-system-label "root-fs")) @@ -626,7 +626,7 @@ where /gnu lives on a separate partition.") (bootloader (bootloader-configuration (bootloader grub-bootloader) - (target "/dev/vdb"))) + (targets (list "/dev/vdb")))) (kernel-arguments '("console=ttyS0")) ;; Add a kernel module for RAID-1 (aka. "mirror"). @@ -842,7 +842,7 @@ build (current-guix) and then store a couple of full system images.") (bootloader (bootloader-configuration (bootloader grub-bootloader) - (target "/dev/vdb"))) + (targets (list "/dev/vdb")))) (kernel-arguments '("console=ttyS0")) (mapped-devices (list (mapped-device @@ -929,7 +929,7 @@ reboot\n") (bootloader (bootloader-configuration (bootloader grub-bootloader) - (target "/dev/vdb"))) + (targets (list "/dev/vdb")))) (mapped-devices (list (mapped-device (source @@ -1029,7 +1029,7 @@ store a couple of full system images.") (bootloader (bootloader-configuration (bootloader grub-bootloader) - (target "/dev/vdb"))) + (targets (list "/dev/vdb")))) (kernel-arguments '("console=ttyS0")) (file-systems (cons (file-system (device (file-system-label "my-root")) @@ -1103,7 +1103,7 @@ build (current-guix) and then store a couple of full system images.") (bootloader (bootloader-configuration (bootloader grub-bootloader) - (target "/dev/vdb"))) + (targets (list "/dev/vdb")))) (kernel-arguments '("console=ttyS0")) (file-systems (cons (file-system @@ -1171,7 +1171,7 @@ RAID-0 (stripe) root partition.") (locale "en_US.UTF-8") (bootloader (bootloader-configuration (bootloader grub-bootloader) - (target "/dev/vdb"))) + (targets (list "/dev/vdb")))) (kernel-arguments '("console=ttyS0")) (file-systems (cons* (file-system (device (file-system-label "btrfs-pool")) @@ -1264,7 +1264,7 @@ build (current-guix) and then store a couple of full system images.") (bootloader (bootloader-configuration (bootloader grub-bootloader) - (target "/dev/vdb"))) + (targets (list "/dev/vdb")))) (kernel-arguments '("console=ttyS0")) (file-systems (cons (file-system (device (file-system-label "my-root")) @@ -1337,7 +1337,7 @@ build (current-guix) and then store a couple of full system images.") (bootloader (bootloader-configuration (bootloader grub-bootloader) - (target "/dev/vdb"))) + (targets (list "/dev/vdb")))) (kernel-arguments '("console=ttyS0")) (file-systems (cons (file-system (device (file-system-label "my-root")) diff --git a/gnu/tests/reconfigure.scm b/gnu/tests/reconfigure.scm index 52beeef447..001b5d185a 100644 --- a/gnu/tests/reconfigure.scm +++ b/gnu/tests/reconfigure.scm @@ -261,7 +261,7 @@ bootloader's configuration file." ;; would attempt to write directly to the virtual disk if the ;; installation script were run. (test - (install-bootloader-program #f #f #f bootcfg bootcfg-file #f "/"))))) + (install-bootloader-program #f #f #f bootcfg bootcfg-file '(#f) "/"))))) (define %test-switch-to-system diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm index 40401d7e03..83bbefd3dc 100644 --- a/guix/scripts/system.scm +++ b/guix/scripts/system.scm @@ -253,7 +253,7 @@ the ownership of '~a' may be incorrect!~%") #:target target) (return (info (G_ "bootloader successfully installed on '~a'~%") - (bootloader-configuration-target bootloader)))))))) + (bootloader-configuration-targets bootloader)))))))) ;;; @@ -768,14 +768,13 @@ and TARGET arguments." skip-safety-checks? install-bootloader? dry-run? derivations-only? - use-substitutes? bootloader-target target + use-substitutes? target full-boot? container-shared-network? (mappings '()) (gc-root #f)) "Perform ACTION for IMAGE. INSTALL-BOOTLOADER? specifies whether to install -bootloader; BOOTLOADER-TAGET is the target for the bootloader; TARGET is the -target root directory. +bootloader; TARGET is the target root directory. FULL-BOOT? is used for the 'vm' action; it determines whether to boot directly to the kernel or to the bootloader. CONTAINER-SHARED-NETWORK? @@ -856,13 +855,13 @@ static checks." #:target (or target "/")) (return (info (G_ "bootloader successfully installed on '~a'~%") - (bootloader-configuration-target bootloader)))) + (bootloader-configuration-targets bootloader)))) (with-shepherd-error-handling - (upgrade-shepherd-services local-eval os) - (return (format #t (G_ "\ + (upgrade-shepherd-services local-eval os) + (return (format #t (G_ "\ To complete the upgrade, run 'herd restart SERVICE' to stop, upgrade, and restart each service that was not automatically restarted.\n"))) - (return (format #t (G_ "\ + (return (format #t (G_ "\ Run 'herd status' to view the list of services on your system.\n")))))) ((init) (newline) @@ -1218,9 +1217,9 @@ resulting from command-line parsing." (target-file (match args ((first second) second) (_ #f))) - (bootloader-target + (bootloader-targets (and bootloader? - (bootloader-configuration-target + (bootloader-configuration-targets (operating-system-bootloader os))))) (define (graph-backend) @@ -1269,7 +1268,6 @@ resulting from command-line parsing." opts) #:install-bootloader? bootloader? #:target target-file - #:bootloader-target bootloader-target #:gc-root (assoc-ref opts 'gc-root))))) #:target target #:system system))) diff --git a/guix/scripts/system/reconfigure.scm b/guix/scripts/system/reconfigure.scm index 49da6ecb16..bf23fb06af 100644 --- a/guix/scripts/system/reconfigure.scm +++ b/guix/scripts/system/reconfigure.scm @@ -207,10 +207,10 @@ services as defined by OS." (define (install-bootloader-program installer disk-installer bootloader-package bootcfg - bootcfg-file device target) + bootcfg-file devices target) "Return an executable store item that, upon being evaluated, will install -BOOTCFG to BOOTCFG-FILE, a target file name, on DEVICE, a file system device, -at TARGET, a mount point, and subsequently run INSTALLER from +BOOTCFG to BOOTCFG-FILE, a target file name, on DEVICES, a list of file system +devices, at TARGET, a mount point, and subsequently run INSTALLER from BOOTLOADER-PACKAGE." (program-file "install-bootloader.scm" @@ -254,11 +254,17 @@ BOOTLOADER-PACKAGE." ;; The bootloader might not support installation on a ;; mounted directory using the BOOTLOADER-INSTALLER ;; procedure. In that case, fallback to installing the - ;; bootloader directly on DEVICE using the + ;; bootloader directly on DEVICES using the ;; BOOTLOADER-DISK-IMAGE-INSTALLER procedure. (if #$installer - (#$installer #$bootloader-package #$device #$target) - (#$disk-installer #$bootloader-package 0 #$device))) + (for-each (lambda (device) + (#$installer #$bootloader-package device + #$target)) + '#$devices) + (for-each (lambda (device) + (#$disk-installer #$bootloader-package + 0 device)) + '#$devices))) (lambda args (delete-file new-gc-root) (match args @@ -284,7 +290,7 @@ additional configurations specified by MENU-ENTRIES can be selected." (disk-installer (and run-installer? (bootloader-disk-image-installer bootloader))) (package (bootloader-package bootloader)) - (device (bootloader-configuration-target configuration)) + (devices (bootloader-configuration-targets configuration)) (bootcfg-file (bootloader-configuration-file bootloader))) (eval #~(parameterize ((current-warning-port (%make-void-port "w"))) (primitive-load #$(install-bootloader-program installer @@ -292,7 +298,7 @@ additional configurations specified by MENU-ENTRIES can be selected." package bootcfg bootcfg-file - device + devices target)))))) diff --git a/tests/guix-system.sh b/tests/guix-system.sh index 7e992e7bdb..6aab1f380a 100644 --- a/tests/guix-system.sh +++ b/tests/guix-system.sh @@ -115,7 +115,7 @@ cat > "$tmpfile" <guix-package): Likewise. Signed-off-by: Ludovic Courtès --- guix/build-system/chicken.scm | 10 +++++++++- guix/import/egg.scm | 5 +++-- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'guix') diff --git a/guix/build-system/chicken.scm b/guix/build-system/chicken.scm index 9abae0431a..10f1469e88 100644 --- a/guix/build-system/chicken.scm +++ b/guix/build-system/chicken.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2020 raingloom +;;; Copyright © 2021 Xinglu Chen ;;; ;;; This file is part of GNU Guix. ;;; @@ -26,7 +27,14 @@ #:use-module (ice-9 match) #:export (%chicken-build-system-modules chicken-build - chicken-build-system)) + chicken-build-system + egg-uri)) + +(define* (egg-uri name version #:optional (extension ".tar.gz")) + "Return a URI string for the CHICKEN egg corresponding to NAME and VERSION. +EXTENSION is the file name extension, such as '.tar.gz'." + (string-append "https://code.call-cc.org/egg-tarballs/5/" + name "/" name "-" version extension)) (define %chicken-build-system-modules ;; Build-side modules imported and used by default. diff --git a/guix/import/egg.scm b/guix/import/egg.scm index 107894ddcf..89e7a9160d 100644 --- a/guix/import/egg.scm +++ b/guix/import/egg.scm @@ -87,7 +87,7 @@ (define (egg-source-url name version) "Return the URL to the source tarball for version VERSION of the CHICKEN egg NAME." - (string-append (%eggs-url) "/" name "/" name "-" version ".tar.gz")) + `(egg-uri ,name version)) (define (egg-name->guix-name name) "Return the package name for CHICKEN egg NAME." @@ -197,7 +197,8 @@ not work." (tarball (if source #f (with-store store - (download-to-store store source-url))))) + (download-to-store + store (egg-uri name version)))))) (define egg-home-page (string-append (%eggs-home-page) "/" name)) -- cgit v1.2.3 From 222f4661ed11b225f458cbe495a296f233129bec Mon Sep 17 00:00:00 2001 From: Mathieu Othacehe Date: Tue, 31 Aug 2021 13:31:57 +0200 Subject: publish: Do not render the narinfo "System" field. This has been discussed here: https://issues.guix.gnu.org/50040. * guix/scripts/publish.scm (narinfo-string): Do not render the "System" field that is expensive to compute and currently unused. --- guix/scripts/publish.scm | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'guix') diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm index 913cbd4fda..f67f81acb1 100644 --- a/guix/scripts/publish.scm +++ b/guix/scripts/publish.scm @@ -4,6 +4,7 @@ ;;; Copyright © 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès ;;; Copyright © 2020 Maxim Cournoyer ;;; Copyright © 2021 Simon Tournier +;;; Copyright © 2021 Mathieu Othacehe ;;; ;;; This file is part of GNU Guix. ;;; @@ -358,20 +359,20 @@ References: ~a~%" compression))) compressions) hash size references)) - ;; Do not render a "Deriver" or "System" line if we are rendering - ;; info for a derivation. + ;; Do not render a "Deriver" line if we are rendering info for a + ;; derivation. Also do not render a "System" line that would be + ;; expensive to compute and is currently unused. (info (if (not deriver) base-info (catch 'system-error (lambda () (let ((drv (read-derivation-from-file deriver))) - (format #f "~aSystem: ~a~%Deriver: ~a~%" - base-info (derivation-system drv) - (basename deriver)))) + (format #f "~aDeriver: ~a~%" + base-info (basename deriver)))) (lambda args ;; DERIVER might be missing, but that's fine: ;; it's only used for where it's - ;; optional. 'System' is currently unused. + ;; optional. (if (= ENOENT (system-error-errno args)) base-info (apply throw args)))))) -- cgit v1.2.3 From 16579a7c576d205ca78b22777d5ea14973faac7e Mon Sep 17 00:00:00 2001 From: Sarah Morgensen Date: Fri, 6 Aug 2021 11:04:43 -0700 Subject: import: go: Return false for package not found. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * guix/import/go.scm (go-module-recursive-import): Explicitly return false when packages are not found. Signed-off-by: Ludovic Courtès --- guix/import/go.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'guix') diff --git a/guix/import/go.scm b/guix/import/go.scm index 617a0d0e23..a4775f973f 100644 --- a/guix/import/go.scm +++ b/guix/import/go.scm @@ -668,7 +668,7 @@ This package and its dependencies won't be imported.~%") (uri->string (http-get-error-uri c)) (http-get-error-code c) (http-get-error-reason c)) - (values '() '()))) + (values #f '()))) (receive (package-sexp dependencies) (go-module->guix-package* name #:goproxy goproxy #:version version -- cgit v1.2.3 From f95bdeb93a30b89c821627aa91da4ef3afaeb5af Mon Sep 17 00:00:00 2001 From: Sarah Morgensen Date: Fri, 6 Aug 2021 11:05:16 -0700 Subject: import: utils: Skip not found packages. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * guix/import/utils.scm (recursive-import): Skip packages when the package returned by 'repo->guix-package' is false. * tests/import-utils.scm: New tests. Signed-off-by: Ludovic Courtès --- guix/import/utils.scm | 26 ++++++++++++++------------ tests/import-utils.scm | 28 ++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 12 deletions(-) (limited to 'guix') diff --git a/guix/import/utils.scm b/guix/import/utils.scm index d1b8076ddd..a180742ca3 100644 --- a/guix/import/utils.scm +++ b/guix/import/utils.scm @@ -8,6 +8,7 @@ ;;; Copyright © 2020 Helio Machado <0x2b3bfa0+guix@googlemail.com> ;;; Copyright © 2020 Martin Becze ;;; Copyright © 2021 Maxim Cournoyer +;;; Copyright © 2021 Sarah Morgensen ;;; ;;; This file is part of GNU Guix. ;;; @@ -489,15 +490,16 @@ to obtain the Guix package name corresponding to the upstream name." (name (list name #f))) dependencies))) (make-node name version package normalized-deps))) - (map node-package - (topological-sort (list (lookup-node package-name version)) - (lambda (node) - (map (lambda (name-version) - (apply lookup-node name-version)) - (remove (lambda (name-version) - (apply exists? name-version)) - (node-dependencies node)))) - (lambda (node) - (string-append - (node-name node) - (or (node-version node) "")))))) + (filter-map + node-package + (topological-sort (list (lookup-node package-name version)) + (lambda (node) + (map (lambda (name-version) + (apply lookup-node name-version)) + (remove (lambda (name-version) + (apply exists? name-version)) + (node-dependencies node)))) + (lambda (node) + (string-append + (node-name node) + (or (node-version node) "")))))) diff --git a/tests/import-utils.scm b/tests/import-utils.scm index 874816442e..7c6c782917 100644 --- a/tests/import-utils.scm +++ b/tests/import-utils.scm @@ -2,6 +2,7 @@ ;;; Copyright © 2015, 2017 Ricardo Wurmus ;;; Copyright © 2016 Ben Woodcroft ;;; Copyright © 2020 Martin Becze +;;; Copyright © 2021 Sarah Morgensen ;;; ;;; This file is part of GNU Guix. ;;; @@ -64,6 +65,33 @@ '()))) #:guix-name identity)) +(test-equal "recursive-import: skip false packages (toplevel)" + '() + (recursive-import "foo" + #:repo 'repo + #:repo->guix-package + (match-lambda* + (("foo" #:version #f #:repo 'repo) + (values #f '()))) + #:guix-name identity)) + +(test-equal "recursive-import: skip false packages (dependency)" + '((package + (name "foo") + (inputs `(("bar" ,bar))))) + (recursive-import "foo" + #:repo 'repo + #:repo->guix-package + (match-lambda* + (("foo" #:version #f #:repo 'repo) + (values '(package + (name "foo") + (inputs `(("bar" ,bar)))) + '("bar"))) + (("bar" #:version #f #:repo 'repo) + (values #f '()))) + #:guix-name identity)) + (test-assert "alist->package with simple source" (let* ((meta '(("name" . "hello") ("version" . "2.10") -- cgit v1.2.3 From be13e2be08feb88d868f911d8f55b0451fe15e10 Mon Sep 17 00:00:00 2001 From: zimoun Date: Fri, 6 Aug 2021 11:05:17 -0700 Subject: import: go: Improve error handling. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * guix/import/go.scm (go-module->guix-package*): Handle errors, remove memoize. (go-module-recursive-import): Remove 'guard', add memoize. * guix/scripts/import/go.scm (guix-import-go): Adjust. * tests/go.scm: Adjust. Signed-off-by: Ludovic Courtès --- guix/import/go.scm | 50 ++++++++++++++++++++++++++++------------------ guix/scripts/import/go.scm | 6 +++--- tests/go.scm | 2 +- 3 files changed, 35 insertions(+), 23 deletions(-) (limited to 'guix') diff --git a/guix/import/go.scm b/guix/import/go.scm index a4775f973f..4755571209 100644 --- a/guix/import/go.scm +++ b/guix/import/go.scm @@ -6,6 +6,7 @@ ;;; Copyright © 2021 Ludovic Courtès ;;; Copyright © 2021 Xinglu Chen ;;; Copyright © 2021 Sarah Morgensen +;;; Copyright © 2021 Simon Tournier ;;; ;;; This file is part of GNU Guix. ;;; @@ -63,6 +64,7 @@ #:use-module (web uri) #:export (go-module->guix-package + go-module->guix-package* go-module-recursive-import)) ;;; Commentary: @@ -646,7 +648,28 @@ hint: use one of the following available versions ~a\n" dependencies+versions dependencies)))) -(define go-module->guix-package* (memoize go-module->guix-package)) +(define go-module->guix-package* + (lambda args + ;; Disable output buffering so that the following warning gets printed + ;; consistently. + (setvbuf (current-error-port) 'none) + (let ((package-name (match args ((name _ ...) name)))) + (guard (c ((http-get-error? c) + (warning (G_ "Failed to import package ~s. +reason: ~s could not be fetched: HTTP error ~a (~s). +This package and its dependencies won't be imported.~%") + package-name + (uri->string (http-get-error-uri c)) + (http-get-error-code c) + (http-get-error-reason c)) + (values #f '())) + (else + (warning (G_ "Failed to import package ~s. +reason: ~s.~%") + package-name + (exception-args c)) + (values #f '()))) + (apply go-module->guix-package args))))) (define* (go-module-recursive-import package-name #:key (goproxy "https://proxy.golang.org") @@ -656,23 +679,12 @@ hint: use one of the following available versions ~a\n" (recursive-import package-name #:repo->guix-package - (lambda* (name #:key version repo) - ;; Disable output buffering so that the following warning gets printed - ;; consistently. - (setvbuf (current-error-port) 'none) - (guard (c ((http-get-error? c) - (warning (G_ "Failed to import package ~s. -reason: ~s could not be fetched: HTTP error ~a (~s). -This package and its dependencies won't be imported.~%") - name - (uri->string (http-get-error-uri c)) - (http-get-error-code c) - (http-get-error-reason c)) - (values #f '()))) - (receive (package-sexp dependencies) - (go-module->guix-package* name #:goproxy goproxy - #:version version - #:pin-versions? pin-versions?) - (values package-sexp dependencies)))) + (memoize + (lambda* (name #:key version repo) + (receive (package-sexp dependencies) + (go-module->guix-package* name #:goproxy goproxy + #:version version + #:pin-versions? pin-versions?) + (values package-sexp dependencies)))) #:guix-name go-module->guix-package-name #:version version)) diff --git a/guix/scripts/import/go.scm b/guix/scripts/import/go.scm index e08a1e427e..f5cfea8683 100644 --- a/guix/scripts/import/go.scm +++ b/guix/scripts/import/go.scm @@ -112,10 +112,10 @@ that are not yet in Guix")) (map package->definition* (apply go-module-recursive-import arguments)) ;; Single import. - (let ((sexp (apply go-module->guix-package arguments))) + (let ((sexp (apply go-module->guix-package* arguments))) (unless sexp - (leave (G_ "failed to download meta-data for module '~a'~%") - module-name)) + (leave (G_ "failed to download meta-data for module '~a'.~%") + name)) (package->definition* sexp)))))) (() (leave (G_ "too few arguments~%"))) diff --git a/tests/go.scm b/tests/go.scm index 6749f4585f..9e7223ff7c 100644 --- a/tests/go.scm +++ b/tests/go.scm @@ -410,6 +410,6 @@ package.") (nix-base32-string->bytevector "0sjjj9z1dhilhpc8pq4154czrb79z9cm044jvn75kxcjv6v5l2m5") #f))) - (go-module->guix-package "github.com/go-check/check"))))))) + (go-module->guix-package* "github.com/go-check/check"))))))) (test-end "go") -- cgit v1.2.3 From e53d8a84c6fbf7641e7d0e6e8658da0bb01fcd71 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Thu, 2 Sep 2021 12:00:02 +0200 Subject: publish: Simplify 'narinfo-string'. This is a followup to 222f4661ed11b225f458cbe495a296f233129bec, which was intended to improve performance of 'narinfo-string'. * guix/scripts/publish.scm (narinfo-string): Remove 'catch' and 'read-derivation-from-file' call when rendering "Deriver". --- guix/scripts/publish.scm | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'guix') diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm index f67f81acb1..25846b7dc2 100644 --- a/guix/scripts/publish.scm +++ b/guix/scripts/publish.scm @@ -364,18 +364,8 @@ References: ~a~%" ;; expensive to compute and is currently unused. (info (if (not deriver) base-info - (catch 'system-error - (lambda () - (let ((drv (read-derivation-from-file deriver))) - (format #f "~aDeriver: ~a~%" - base-info (basename deriver)))) - (lambda args - ;; DERIVER might be missing, but that's fine: - ;; it's only used for where it's - ;; optional. - (if (= ENOENT (system-error-errno args)) - base-info - (apply throw args)))))) + (format #f "~aDeriver: ~a~%" + base-info (basename deriver)))) (signature (base64-encode-string (canonical-sexp->string (signed-string info))))) (format #f "~aSignature: 1;~a;~a~%" info (gethostname) signature))) -- cgit v1.2.3 From 9540323458de87b0b8aa421e449a4fe27af7c393 Mon Sep 17 00:00:00 2001 From: Christopher Baines Date: Sun, 1 Aug 2021 16:23:57 +0100 Subject: weather: Don't look for exported package replacements twice. * guix/scripts/weather.scm (all-packages): Delete duplicates, so that exported replacements aren't included twice. --- guix/scripts/weather.scm | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'guix') diff --git a/guix/scripts/weather.scm b/guix/scripts/weather.scm index 06312d65a2..60a697d1ac 100644 --- a/guix/scripts/weather.scm +++ b/guix/scripts/weather.scm @@ -54,16 +54,18 @@ (define (all-packages) "Return the list of public packages we are going to query." - (fold-packages (lambda (package result) - (match (package-replacement package) - ((? package? replacement) - (cons* replacement package result)) - (#f - (cons package result)))) - '() - - ;; Dismiss deprecated packages but keep hidden packages. - #:select? (negate package-superseded))) + (delete-duplicates + (fold-packages (lambda (package result) + (match (package-replacement package) + ((? package? replacement) + (cons* replacement package result)) + (#f + (cons package result)))) + '() + + ;; Dismiss deprecated packages but keep hidden packages. + #:select? (negate package-superseded)) + eq?)) (define (call-with-progress-reporter reporter proc) "This is a variant of 'call-with-progress-reporter' that works with monadic -- cgit v1.2.3 From b452c3b37a09e0d52b55c301a916074760efbafa Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 6 Sep 2021 11:33:10 +0200 Subject: swh: Export accessors. * guix/swh.scm: Export accessors. --- guix/swh.scm | 3 +++ 1 file changed, 3 insertions(+) (limited to 'guix') diff --git a/guix/swh.scm b/guix/swh.scm index b5c800011d..7b14a70693 100644 --- a/guix/swh.scm +++ b/guix/swh.scm @@ -55,6 +55,9 @@ visit-number visit-snapshot + snapshot? + snapshot-branches + branch? branch-name branch-target -- cgit v1.2.3 From 63ed618e337a466772aadd6ef3b919b7f04b666d Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 6 Sep 2021 14:03:28 +0200 Subject: swh: accept null 'date' fields. * guix/swh.scm (maybe-null): New procedure. ()[date]: Use it. --- guix/swh.scm | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'guix') diff --git a/guix/swh.scm b/guix/swh.scm index 7b14a70693..4d0a647d6f 100644 --- a/guix/swh.scm +++ b/guix/swh.scm @@ -186,6 +186,12 @@ Software Heritage." (ref 10)))))) str)) ;oops! +(define (maybe-null proc) + (match-lambda + ((? null?) #f) + ('null #f) + (obj (proc obj)))) + (define string* ;; Converts "string or #nil" coming from JSON to "string or #f". (match-lambda @@ -319,10 +325,13 @@ FALSE-IF-404? is true, return #f upon 404 responses." (target-url release-target-url "target_url")) ;; +;; Note: Some revisions, such as those for "nixguix" origins (e.g., +;; ), +;; have their 'date' field set to null. (define-json-mapping make-revision revision? json->revision (id revision-id) - (date revision-date "date" string->date*) + (date revision-date "date" (maybe-null string->date*)) (directory revision-directory) (directory-url revision-directory-url "directory_url")) -- cgit v1.2.3 From 153fd217b62a3d57d00f2ce440cf010f5070e886 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 6 Sep 2021 15:43:04 +0200 Subject: swh: Add 'lookup-snapshot-branch'. * guix/swh.scm ()[id]: New field. (snapshot-url, lookup-snapshot-branch): New procedures. --- guix/swh.scm | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'guix') diff --git a/guix/swh.scm b/guix/swh.scm index 4d0a647d6f..922d781a7b 100644 --- a/guix/swh.scm +++ b/guix/swh.scm @@ -56,7 +56,9 @@ visit-snapshot snapshot? + snapshot-id snapshot-branches + lookup-snapshot-branch branch? branch-name @@ -296,6 +298,7 @@ FALSE-IF-404? is true, return #f upon 404 responses." ;; (define-json-mapping make-snapshot snapshot? json->snapshot + (id snapshot-id) (branches snapshot-branches "branches" json->branches)) ;; This is used for the "branches" field of snapshots. @@ -438,6 +441,32 @@ available." (call (swh-url (visit-snapshot-url visit)) json->snapshot))) +(define (snapshot-url snapshot branch-count first-branch) + "Return the URL of SNAPSHOT such that it contains information for +BRANCH-COUNT branches, starting at FIRST-BRANCH." + (string-append (swh-url "/api/1/snapshot" (snapshot-id snapshot)) + "?branches_count=" (number->string branch-count) + "&branches_from=" (uri-encode first-branch))) + +(define (lookup-snapshot-branch snapshot name) + "Look up branch NAME on SNAPSHOT. Return the branch, or return #f if it +could not be found." + (or (find (lambda (branch) + (string=? (branch-name branch) name)) + (snapshot-branches snapshot)) + + ;; There's no API entry point to look up a snapshot branch by name. + ;; Work around that by using the paginated list of branches provided by + ;; the /api/1/snapshot API: ask for one branch, and start pagination at + ;; NAME. + (let ((snapshot (call (snapshot-url snapshot 1 name) + json->snapshot))) + (match (snapshot-branches snapshot) + ((branch) + (and (string=? (branch-name branch) name) + branch)) + (_ #f))))) + (define (branch-target branch) "Return the target of BRANCH, either a or a ." (match (branch-target-type branch) -- cgit v1.2.3