From 81c3dc32244a17241d74eea9fa265edfcb326f6d Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Sun, 21 Jul 2019 23:05:54 +0200 Subject: maint: Switch to Guile-JSON 3.x. Guile-JSON 3.x is incompatible with Guile-JSON 1.x, which we relied on until now: it maps JSON dictionaries to alists (instead of hash tables), and JSON arrays to vectors (instead of lists). This commit is about adjusting all the existing code to this new mapping. * m4/guix.m4 (GUIX_CHECK_GUILE_JSON): New macro. * configure.ac: Use it. * doc/guix.texi (Requirements): Mention the Guile-JSON version. * guix/git-download.scm (git-fetch)[guile-json]: Use GUILE-JSON-3. * guix/import/cpan.scm (string->license): Expect vectors instead of lists. (module->dist-name): Use 'json-fetch' instead of 'json-fetch-alist'. (cpan-fetch): Likewise. * guix/import/crate.scm (crate-fetch): Likewise, and call 'vector->list' for DEPS. * guix/import/gem.scm (rubygems-fetch): Likewise. * guix/import/json.scm (json-fetch-alist): Remove. * guix/import/pypi.scm (pypi-fetch): Use 'json-fetch' instead of 'json-fetch-alist'. (latest-source-release, latest-wheel-release): Call 'vector->list' on RELEASES. * guix/import/stackage.scm (stackage-lts-info-fetch): Use 'json-fetch' instead of 'json-fetch-alist'. (lts-package-version): Use 'vector->list'. * guix/import/utils.scm (hash-table->alist): Remove. (alist->package): Pass 'vector->list' on the inputs fields, and default to the empty vector. * guix/scripts/import/json.scm (guix-import-json): Remove call to 'hash-table->alist'. * guix/swh.scm (define-json-reader): Expect pair? or null? instead of hash-table?. [extract-field]: Use 'assoc-ref' instead of 'hash-ref'. (json->branches): Use 'map' instead of 'hash-map->list'. (json->checksums): Likewise. (json->directory-entries, origin-visits): Call 'vector->list' on the result of 'json->scm'. * tests/import-utils.scm ("alist->package with dependencies"): New test. * gnu/installer.scm (build-compiled-file)[builder]: Use GUILE-JSON-3. * gnu/installer.scm (installer-program)[installer-builder]: Likewise. * gnu/installer/locale.scm (iso639->iso639-languages): Use 'assoc-ref' instead of 'hash-ref', and pass vectors through 'vector->list'. (iso3166->iso3166-territories): Likewise. * gnu/system/vm.scm (system-docker-image)[build]: Use GUILE-JSON-3. * guix/docker.scm (manifest, config): Adjust for Guile-JSON 3. * guix/scripts/pack.scm (docker-image)[build]: Use GUILE-JSON-3. * guix/import/github.scm (fetch-releases-or-tags): Update docstring. (latest-released-version): Use 'assoc-ref' instead of 'hash-ref'. Pass the result of 'fetch-releases-or-tags' to 'vector->list'. * guix/import/launchpad.scm (latest-released-version): Likewise. --- tests/import-utils.scm | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'tests') diff --git a/tests/import-utils.scm b/tests/import-utils.scm index 5c0c041360..c3ab25d788 100644 --- a/tests/import-utils.scm +++ b/tests/import-utils.scm @@ -23,6 +23,7 @@ #:use-module ((guix licenses) #:prefix license:) #:use-module (guix packages) #:use-module (guix build-system) + #:use-module (gnu packages) #:use-module (srfi srfi-64)) (test-begin "import-utils") @@ -98,4 +99,25 @@ (or (package-license (alist->package meta)) 'license-is-false))) +(test-equal "alist->package with dependencies" + `(("gettext" ,(specification->package "gettext"))) + (let* ((meta '(("name" . "hello") + ("version" . "2.10") + ("source" . (("method" . "url-fetch") + ("uri" . "mirror://gnu/hello/hello-2.10.tar.gz") + ("sha256" . + (("base32" . + "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"))))) + ("build-system" . "gnu") + ("home-page" . "https://gnu.org") + ("synopsis" . "Say hi") + ("description" . "This package says hi.") + ; + ;; Note: As with Guile-JSON 3.x, JSON arrays are represented + ;; by vectors. + ("native-inputs" . #("gettext")) + + ("license" . #f)))) + (package-native-inputs (alist->package meta)))) + (test-end "import-utils") -- cgit 1.4.1 From 177fecb57c0c9e15249bf6a49244c9dc6eb8439c Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Fri, 26 Jul 2019 11:09:56 +0200 Subject: git: allows tags in its 'commit' field. Fixes . Reported by Tobias Geerinckx-Rice . * guix/git.scm (git-checkout-compiler): Pass 'tag-or-commit' to 'latest-repository-commit*'. * doc/guix.texi (Package Transformation Options): Update '--with-commit' documentation accordingly. * tests/guix-build-branch.sh: Add test. --- doc/guix.texi | 2 +- guix/git.scm | 4 ++-- tests/guix-build-branch.sh | 8 +++++++- 3 files changed, 10 insertions(+), 4 deletions(-) (limited to 'tests') diff --git a/doc/guix.texi b/doc/guix.texi index c2da4ce173..96448c24e5 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -8048,7 +8048,7 @@ guix build --with-branch=guile-sqlite3=master cuirass @item --with-commit=@var{package}=@var{commit} This is similar to @code{--with-branch}, except that it builds from @var{commit} rather than the tip of a branch. @var{commit} must be a valid -Git commit SHA1 identifier. +Git commit SHA1 identifier or a tag. @end table @node Additional Build Options diff --git a/guix/git.scm b/guix/git.scm index fb2df2de07..85252629fc 100644 --- a/guix/git.scm +++ b/guix/git.scm @@ -330,7 +330,7 @@ Log progress and checkout info to LOG-PORT." git-checkout? (url git-checkout-url) (branch git-checkout-branch (default "master")) - (commit git-checkout-commit (default #f)) + (commit git-checkout-commit (default #f)) ;#f | tag | commit (recursive? git-checkout-recursive? (default #f))) (define* (latest-repository-commit* url #:key ref recursive? log-port) @@ -369,7 +369,7 @@ Log progress and checkout info to LOG-PORT." (($ url branch commit recursive?) (latest-repository-commit* url #:ref (if commit - `(commit . ,commit) + `(tag-or-commit . ,commit) `(branch . ,branch)) #:recursive? recursive? #:log-port (current-error-port))))) diff --git a/tests/guix-build-branch.sh b/tests/guix-build-branch.sh index e64782c831..0cec7c75db 100644 --- a/tests/guix-build-branch.sh +++ b/tests/guix-build-branch.sh @@ -1,5 +1,5 @@ # GNU Guix --- Functional package management for GNU -# Copyright © 2018 Ludovic Courtès +# Copyright © 2018, 2019 Ludovic Courtès # # This file is part of GNU Guix. # @@ -52,5 +52,11 @@ guix gc -R "$v0_1_0_drv" | grep guile-gcrypt-git.9e3eacd test "$v0_1_0_drv" != "$latest_drv" test "$v0_1_0_drv" != "$orig_drv" +v0_1_0_drv="`guix build guix --with-commit=guile-gcrypt=v0.1.0 -d`" +guix gc -R "$v0_1_0_drv" | grep guile-gcrypt-git.v0.1.0 +guix gc -R "$v0_1_0_drv" | grep guile-gcrypt-8fe64e8 # this is the *tag* ID +test "$v0_1_0_drv" != "$latest_drv" +test "$v0_1_0_drv" != "$orig_drv" + if guix build guix --with-commit=guile-gcrypt=000 -d then false; else true; fi -- cgit 1.4.1 From 10a8c2bbc6754bddb0e5d668b3ecc9050efd820b Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Fri, 26 Jul 2019 11:16:10 +0200 Subject: git: 'switch-to-ref' resolves tag targets. * guix/git.scm (switch-to-ref): In the 'tag' case, resolve the target of the tag. * tests/guix-build-branch.sh: Adjust test accordingly. --- guix/git.scm | 6 +++++- tests/guix-build-branch.sh | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/guix/git.scm b/guix/git.scm index 85252629fc..de98fed40c 100644 --- a/guix/git.scm +++ b/guix/git.scm @@ -172,7 +172,11 @@ OID (roughly the commit hash) corresponding to REF." (('tag . tag) (let ((oid (reference-name->oid repository (string-append "refs/tags/" tag)))) - (object-lookup repository oid)))))) + ;; Get the commit that the tag at OID refers to. This is not + ;; strictly needed, but it's more consistent to always return the + ;; OID of a commit. + (object-lookup repository + (tag-target-id (tag-lookup repository oid)))))))) (reset repository obj RESET_HARD) (object-id obj)) diff --git a/tests/guix-build-branch.sh b/tests/guix-build-branch.sh index 0cec7c75db..3d2a7dddf5 100644 --- a/tests/guix-build-branch.sh +++ b/tests/guix-build-branch.sh @@ -54,7 +54,7 @@ test "$v0_1_0_drv" != "$orig_drv" v0_1_0_drv="`guix build guix --with-commit=guile-gcrypt=v0.1.0 -d`" guix gc -R "$v0_1_0_drv" | grep guile-gcrypt-git.v0.1.0 -guix gc -R "$v0_1_0_drv" | grep guile-gcrypt-8fe64e8 # this is the *tag* ID +guix gc -R "$v0_1_0_drv" | grep guile-gcrypt-9e3eacd test "$v0_1_0_drv" != "$latest_drv" test "$v0_1_0_drv" != "$orig_drv" -- cgit 1.4.1 From 5c793753b31b1dcd9a554bce953124f7ae88ca9a Mon Sep 17 00:00:00 2001 From: "Jakob L. Kreuze" Date: Wed, 24 Jul 2019 12:34:02 -0400 Subject: guix system: Add 'reconfigure' module. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * guix/scripts/system/reconfigure.scm: New file. * Makefile.am (MODULES): Add it. * guix/scripts/system.scm (bootloader-installer-script): Export variable. * gnu/machine/ssh.scm (switch-to-system, upgrade-shepherd-services) (install-bootloader): Delete variable. * gnu/machine/ssh.scm (deploy-managed-host): Rewrite procedure. * gnu/services/herd.scm (live-service): Export variable. * gnu/services/herd.scm (live-service-canonical-name): New variable. * tests/services.scm (live-service): Delete variable. Signed-off-by: Ludovic Courtès --- Makefile.am | 1 + gnu/machine/ssh.scm | 189 ++-------------------------- gnu/services/herd.scm | 6 + guix/scripts/system/reconfigure.scm | 237 ++++++++++++++++++++++++++++++++++++ tests/services.scm | 4 - 5 files changed, 256 insertions(+), 181 deletions(-) create mode 100644 guix/scripts/system/reconfigure.scm (limited to 'tests') diff --git a/Makefile.am b/Makefile.am index 7fa51d17ac..0bd85e8fcf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -249,6 +249,7 @@ MODULES = \ guix/scripts/describe.scm \ guix/scripts/system.scm \ guix/scripts/system/search.scm \ + guix/scripts/system/reconfigure.scm \ guix/scripts/lint.scm \ guix/scripts/challenge.scm \ guix/scripts/import/crate.scm \ diff --git a/gnu/machine/ssh.scm b/gnu/machine/ssh.scm index 278d43c10f..552eafa9de 100644 --- a/gnu/machine/ssh.scm +++ b/gnu/machine/ssh.scm @@ -17,23 +17,21 @@ ;;; along with GNU Guix. If not, see . (define-module (gnu machine ssh) - #:use-module (gnu bootloader) #:use-module (gnu machine) #:autoload (gnu packages gnupg) (guile-gcrypt) - #:use-module (gnu services) - #:use-module (gnu services shepherd) #:use-module (gnu system) - #:use-module (guix derivations) #:use-module (guix gexp) #:use-module (guix i18n) #:use-module (guix modules) #:use-module (guix monads) #:use-module (guix records) #:use-module (guix remote) + #:use-module (guix scripts system reconfigure) #:use-module (guix ssh) #:use-module (guix store) #:use-module (ice-9 match) #:use-module (srfi srfi-19) + #:use-module (srfi srfi-26) #:use-module (srfi srfi-35) #:export (managed-host-environment-type @@ -105,118 +103,6 @@ an environment type of 'managed-host." ;;; System deployment. ;;; -(define (switch-to-system machine) - "Monadic procedure creating a new generation on MACHINE and execute the -activation script for the new system configuration." - (define (remote-exp drv script) - (with-extensions (list guile-gcrypt) - (with-imported-modules (source-module-closure '((guix config) - (guix profiles) - (guix utils))) - #~(begin - (use-modules (guix config) - (guix profiles) - (guix utils)) - - (define %system-profile - (string-append %state-directory "/profiles/system")) - - (let* ((system #$drv) - (number (1+ (generation-number %system-profile))) - (generation (generation-file-name %system-profile number))) - (switch-symlinks generation system) - (switch-symlinks %system-profile generation) - ;; The implementation of 'guix system reconfigure' saves the - ;; load path and environment here. This is unnecessary here - ;; because each invocation of 'remote-eval' runs in a distinct - ;; Guile REPL. - (setenv "GUIX_NEW_SYSTEM" system) - ;; The activation script may write to stdout, which confuses - ;; 'remote-eval' when it attempts to read a result from the - ;; remote REPL. We work around this by forcing the output to a - ;; string. - (with-output-to-string - (lambda () - (primitive-load #$script)))))))) - - (let* ((os (machine-system machine)) - (script (operating-system-activation-script os))) - (mlet* %store-monad ((drv (operating-system-derivation os))) - (machine-remote-eval machine (remote-exp drv script))))) - -;; XXX: Currently, this does NOT attempt to restart running services. This is -;; also the case with 'guix system reconfigure'. -;; -;; See . -(define (upgrade-shepherd-services machine) - "Monadic procedure unloading and starting services on the remote as needed -to realize the MACHINE's system configuration." - (define target-services - ;; Monadic expression evaluating to a list of (name output-path) pairs for - ;; all of MACHINE's services. - (mapm %store-monad - (lambda (service) - (mlet %store-monad ((file ((compose lower-object - shepherd-service-file) - service))) - (return (list (shepherd-service-canonical-name service) - (derivation->output-path file))))) - (service-value - (fold-services (operating-system-services (machine-system machine)) - #:target-type shepherd-root-service-type)))) - - (define (remote-exp target-services) - (with-imported-modules '((gnu services herd)) - #~(begin - (use-modules (gnu services herd) - (srfi srfi-1)) - - (define running - (filter live-service-running (current-services))) - - (define (essential? service) - ;; Return #t if SERVICE is essential and should not be unloaded - ;; under any circumstance. - (memq (first (live-service-provision service)) - '(root shepherd))) - - (define (obsolete? service) - ;; Return #t if SERVICE can be safely unloaded. - (and (not (essential? service)) - (every (lambda (requirements) - (not (memq (first (live-service-provision service)) - requirements))) - (map live-service-requirement running)))) - - (define to-unload - (filter obsolete? - (remove (lambda (service) - (memq (first (live-service-provision service)) - (map first '#$target-services))) - running))) - - (define to-start - (remove (lambda (service-pair) - (memq (first service-pair) - (map (compose first live-service-provision) - running))) - '#$target-services)) - - ;; Unload obsolete services. - (for-each (lambda (service) - (false-if-exception - (unload-service service))) - to-unload) - - ;; Load the service files for any new services and start them. - (load-services/safe (map second to-start)) - (for-each start-service (map first to-start)) - - #t))) - - (mlet %store-monad ((target-services target-services)) - (machine-remote-eval machine (remote-exp target-services)))) - (define (machine-boot-parameters machine) "Monadic procedure returning a list of 'boot-parameters' for the generations of MACHINE's system profile, ordered from most recent to oldest." @@ -275,71 +161,20 @@ of MACHINE's system profile, ordered from most recent to oldest." (boot-parameters-kernel-arguments params)))))))) generations)))) -(define (install-bootloader machine) - "Create a bootloader entry for the new system generation on MACHINE, and -configure the bootloader to boot that generation by default." - (define bootloader-installer-script - (@@ (guix scripts system) bootloader-installer-script)) - - (define (remote-exp installer bootcfg bootcfg-file) - (with-extensions (list guile-gcrypt) - (with-imported-modules (source-module-closure '((gnu build install) - (guix store) - (guix utils))) - #~(begin - (use-modules (gnu build install) - (guix store) - (guix utils)) - (let* ((gc-root (string-append "/" %gc-roots-directory "/bootcfg")) - (temp-gc-root (string-append gc-root ".new"))) - - (switch-symlinks temp-gc-root gc-root) - - (unless (false-if-exception - (begin - ;; The implementation of 'guix system reconfigure' - ;; saves the load path here. This is unnecessary here - ;; because each invocation of 'remote-eval' runs in a - ;; distinct Guile REPL. - (install-boot-config #$bootcfg #$bootcfg-file "/") - ;; The installation script may write to stdout, which - ;; confuses 'remote-eval' when it attempts to read a - ;; result from the remote REPL. We work around this - ;; by forcing the output to a string. - (with-output-to-string - (lambda () - (primitive-load #$installer))))) - (delete-file temp-gc-root) - (error "failed to install bootloader")) - - (rename-file temp-gc-root gc-root) - #t))))) - - (mlet* %store-monad ((boot-parameters (machine-boot-parameters machine))) - (let* ((os (machine-system machine)) - (bootloader ((compose bootloader-configuration-bootloader - operating-system-bootloader) - os)) - (bootloader-target (bootloader-configuration-target - (operating-system-bootloader os))) - (installer (bootloader-installer-script - (bootloader-installer bootloader) - (bootloader-package bootloader) - bootloader-target - "/")) - (menu-entries (map boot-parameters->menu-entry boot-parameters)) - (bootcfg (operating-system-bootcfg os menu-entries)) - (bootcfg-file (bootloader-configuration-file bootloader))) - (machine-remote-eval machine (remote-exp installer bootcfg bootcfg-file))))) - (define (deploy-managed-host machine) "Internal implementation of 'deploy-machine' for MACHINE instances with an environment type of 'managed-host." (maybe-raise-unsupported-configuration-error machine) - (mbegin %store-monad - (switch-to-system machine) - (upgrade-shepherd-services machine) - (install-bootloader machine))) + (mlet %store-monad ((boot-parameters (machine-boot-parameters machine))) + (let* ((os (machine-system machine)) + (eval (cut machine-remote-eval machine <>)) + (menu-entries (map boot-parameters->menu-entry boot-parameters)) + (bootloader-configuration (operating-system-bootloader os)) + (bootcfg (operating-system-bootcfg os menu-entries))) + (mbegin %store-monad + (switch-to-system eval os) + (upgrade-shepherd-services eval os) + (install-bootloader eval bootloader-configuration bootcfg))))) ;;; diff --git a/gnu/services/herd.scm b/gnu/services/herd.scm index 0008746fe9..2207b2d34b 100644 --- a/gnu/services/herd.scm +++ b/gnu/services/herd.scm @@ -40,10 +40,12 @@ unknown-shepherd-error? unknown-shepherd-error-sexp + live-service live-service? live-service-provision live-service-requirement live-service-running + live-service-canonical-name with-shepherd-action current-services @@ -192,6 +194,10 @@ of pairs." (requirement live-service-requirement) ;list of symbols (running live-service-running)) ;#f | object +(define (live-service-canonical-name service) + "Return the 'canonical name' of SERVICE." + (first (live-service-provision service))) + (define (current-services) "Return the list of currently defined Shepherd services, represented as objects. Return #f if the list of services could not be diff --git a/guix/scripts/system/reconfigure.scm b/guix/scripts/system/reconfigure.scm new file mode 100644 index 0000000000..8c7d461585 --- /dev/null +++ b/guix/scripts/system/reconfigure.scm @@ -0,0 +1,237 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès +;;; Copyright © 2016 Alex Kost +;;; Copyright © 2016, 2017, 2018 Chris Marusich +;;; Copyright © 2017 Mathieu Othacehe +;;; Copyright © 2018 Ricardo Wurmus +;;; Copyright © 2019 Christopher Baines +;;; Copyright © 2019 Jakob L. Kreuze +;;; +;;; 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 system reconfigure) + #:autoload (gnu packages gnupg) (guile-gcrypt) + #:use-module (gnu bootloader) + #:use-module (gnu services) + #:use-module (gnu services herd) + #:use-module (gnu services shepherd) + #:use-module (gnu system) + #:use-module (guix gexp) + #:use-module (guix modules) + #:use-module (guix monads) + #:use-module (guix store) + #:use-module (ice-9 match) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-11) + #:export (switch-system-program + switch-to-system + + upgrade-services-program + upgrade-shepherd-services + + install-bootloader-program + install-bootloader)) + +;;; Commentary: +;;; +;;; This module implements the "effectful" parts of system +;;; reconfiguration. Although building a system derivation is a pure +;;; operation, a number of impure operations must be carried out for the +;;; system configuration to be realized -- chiefly, creation of generation +;;; symlinks and invocation of activation scripts. +;;; +;;; Code: + + +;;; +;;; Profile creation. +;;; + +(define* (switch-system-program os #:optional profile) + "Return an executable store item that, upon being evaluated, will create a +new generation of PROFILE pointing to the directory of OS, switch to it +atomically, and run OS's activation script." + (program-file + "switch-to-system.scm" + (with-extensions (list guile-gcrypt) + (with-imported-modules (source-module-closure '((guix config) + (guix profiles) + (guix utils))) + #~(begin + (use-modules (guix config) + (guix profiles) + (guix utils)) + + (define profile + (or #$profile (string-append %state-directory "/profiles/system"))) + + (let* ((number (1+ (generation-number profile))) + (generation (generation-file-name profile number))) + (switch-symlinks generation #$os) + (switch-symlinks profile generation) + (setenv "GUIX_NEW_SYSTEM" #$os) + (primitive-load #$(operating-system-activation-script os)))))))) + +(define* (switch-to-system eval os #:optional profile) + "Using EVAL, a monadic procedure taking a single G-Expression as an argument, +create a new generation of PROFILE pointing to the directory of OS, switch to +it atomically, and run OS's activation script." + (eval #~(primitive-load #$(switch-system-program os profile)))) + + +;;; +;;; Services. +;;; + +(define (running-services eval) + "Using EVAL, a monadic procedure taking a single G-Expression as an argument, +return the objects that are currently running on MACHINE." + (define exp + (with-imported-modules '((gnu services herd)) + #~(begin + (use-modules (gnu services herd)) + (let ((services (current-services))) + (and services + ;; 'live-service-running' is ignored, as we can't necessarily + ;; serialize arbitrary objects. This should be fine for now, + ;; since 'machine-current-services' is not exposed publicly, + ;; and the resultant objects are only used for + ;; resolving service dependencies. + (map (lambda (service) + (list (live-service-provision service) + (live-service-requirement service))) + services)))))) + (mlet %store-monad ((services (eval exp))) + (return (map (match-lambda + ((provision requirement) + (live-service provision requirement #f))) + services)))) + +;; XXX: Currently, this does NOT attempt to restart running services. See +;; for details. +(define (upgrade-services-program service-files to-start to-unload to-restart) + "Return an executable store item that, upon being evaluated, will upgrade +the Shepherd (PID 1) by unloading obsolete services and loading new +services. SERVICE-FILES is a list of Shepherd service files to load, and +TO-START, TO-UNLOAD, and TO-RESTART are lists of the Shepherd services' +canonical names (symbols)." + (program-file + "upgrade-shepherd-services.scm" + (with-imported-modules '((gnu services herd)) + #~(begin + (use-modules (gnu services herd) + (srfi srfi-1)) + + ;; Load the service files for any new services. + (load-services/safe '#$service-files) + + ;; Unload obsolete services and start new services. + (for-each unload-service '#$to-unload) + (for-each start-service '#$to-start))))) + +(define* (upgrade-shepherd-services eval os) + "Using EVAL, a monadic procedure taking a single G-Expression as an argument, +upgrade the Shepherd (PID 1) by unloading obsolete services and loading new +services as defined by OS." + (define target-services + (service-value + (fold-services (operating-system-services os) + #:target-type shepherd-root-service-type))) + + (mlet* %store-monad ((live-services (running-services eval))) + (let*-values (((to-unload to-restart) + (shepherd-service-upgrade live-services target-services))) + (let* ((to-unload (map live-service-canonical-name to-unload)) + (to-restart (map shepherd-service-canonical-name to-restart)) + (to-start (lset-difference eqv? + (map shepherd-service-canonical-name + target-services) + (map live-service-canonical-name + live-services))) + (service-files + (map shepherd-service-file + (filter (lambda (service) + (memq (shepherd-service-canonical-name service) + to-start)) + target-services)))) + (eval #~(primitive-load #$(upgrade-services-program service-files + to-start + to-unload + to-restart))))))) + + +;;; +;;; Bootloader configuration. +;;; + +(define (install-bootloader-program installer bootloader-package bootcfg + bootcfg-file device 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 +BOOTLOADER-PACKAGE." + (program-file + "install-bootloader.scm" + (with-extensions (list guile-gcrypt) + (with-imported-modules (source-module-closure '((gnu build bootloader) + (gnu build install) + (guix store) + (guix utils))) + #~(begin + (use-modules (gnu build bootloader) + (gnu build install) + (guix build utils) + (guix store) + (guix utils) + (ice-9 binary-ports) + (srfi srfi-34) + (srfi srfi-35)) + (let* ((gc-root (string-append #$target %gc-roots-directory "/bootcfg")) + (temp-gc-root (string-append gc-root ".new"))) + (switch-symlinks temp-gc-root gc-root) + (install-boot-config #$bootcfg #$bootcfg-file #$target) + ;; Preserve the previous activation's garbage collector root + ;; until the bootloader installer has run, so that a failure in + ;; the bootloader's installer script doesn't leave the user with + ;; a broken installation. + (when #$installer + (catch #t + (lambda () + (#$installer #$bootloader-package #$device #$target)) + (lambda args + (delete-file temp-gc-root) + (apply throw args)))) + (rename-file temp-gc-root gc-root))))))) + +(define* (install-bootloader eval configuration bootcfg + #:key + (run-installer? #t) + (target "/")) + "Using EVAL, a monadic procedure taking a single G-Expression as an argument, +configure the bootloader on TARGET such that OS will be booted by default and +additional configurations specified by MENU-ENTRIES can be selected." + (let* ((bootloader (bootloader-configuration-bootloader configuration)) + (installer (and run-installer? + (bootloader-installer bootloader))) + (package (bootloader-package bootloader)) + (device (bootloader-configuration-target configuration)) + (bootcfg-file (bootloader-configuration-file bootloader))) + (eval #~(primitive-load #$(install-bootloader-program installer + package + bootcfg + bootcfg-file + device + target))))) diff --git a/tests/services.scm b/tests/services.scm index 44ad0022c6..572fe38164 100644 --- a/tests/services.scm +++ b/tests/services.scm @@ -26,10 +26,6 @@ #:use-module (srfi srfi-64) #:use-module (ice-9 match)) -(define live-service - (@@ (gnu services herd) live-service)) - - (test-begin "services") (test-equal "services, default value" -- cgit 1.4.1 From 2e8cabb8d630a8423e2e5a3bf150c1c0310b945d Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Fri, 26 Jul 2019 23:48:03 +0200 Subject: gexp: 'program-file' honors the current system and cross-compilation target. Fixes . Reported by Jakob L. Kreuze . * guix/gexp.scm (program-file-compiler): Pass #:system and #:target to 'gexp->script'. (load-path-expression): Add #:system and #:target and honor them. (gexp->script): Likewise. * tests/gexp.scm ("program-file #:system"): New test. * doc/guix.texi (G-Expressions): Adjust accordingly. --- doc/guix.texi | 3 ++- guix/gexp.scm | 23 +++++++++++++++++------ tests/gexp.scm | 19 +++++++++++++++++++ 3 files changed, 38 insertions(+), 7 deletions(-) (limited to 'tests') diff --git a/doc/guix.texi b/doc/guix.texi index 96448c24e5..ccc36a8a97 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -7439,7 +7439,8 @@ This is the declarative counterpart of @code{gexp->derivation}. @end deffn @deffn {Monadic Procedure} gexp->script @var{name} @var{exp} @ - [#:guile (default-guile)] [#:module-path %load-path] + [#:guile (default-guile)] [#:module-path %load-path] @ + [#:system (%current-system)] [#:target #f] Return an executable script @var{name} that runs @var{exp} using @var{guile}, with @var{exp}'s imported modules in its search path. Look up @var{exp}'s modules in @var{module-path}. diff --git a/guix/gexp.scm b/guix/gexp.scm index a83d7168d2..45cd5869f7 100644 --- a/guix/gexp.scm +++ b/guix/gexp.scm @@ -427,7 +427,9 @@ This is the declarative counterpart of 'gexp->script'." (($ name gexp guile module-path) (gexp->script name gexp #:module-path module-path - #:guile (or guile (default-guile)))))) + #:guile (or guile (default-guile)) + #:system system + #:target target)))) (define-record-type (%scheme-file name gexp splice?) @@ -1512,7 +1514,7 @@ TARGET, a GNU triplet." 'guile-2.2)) (define* (load-path-expression modules #:optional (path %load-path) - #:key (extensions '())) + #:key (extensions '()) system target) "Return as a monadic value a gexp that sets '%load-path' and '%load-compiled-path' to point to MODULES, a list of module names. MODULES are searched for in PATH. Return #f when MODULES and EXTENSIONS are empty." @@ -1520,10 +1522,13 @@ are searched for in PATH. Return #f when MODULES and EXTENSIONS are empty." (with-monad %store-monad (return #f)) (mlet %store-monad ((modules (imported-modules modules - #:module-path path)) + #:module-path path + #:system system)) (compiled (compiled-modules modules #:extensions extensions - #:module-path path))) + #:module-path path + #:system system + #:target target))) (return (gexp (eval-when (expand load eval) (set! %load-path (cons (ungexp modules) @@ -1545,14 +1550,18 @@ are searched for in PATH. Return #f when MODULES and EXTENSIONS are empty." (define* (gexp->script name exp #:key (guile (default-guile)) - (module-path %load-path)) + (module-path %load-path) + (system (%current-system)) + target) "Return an executable script NAME that runs EXP using GUILE, with EXP's imported modules in its search path. Look up EXP's modules in MODULE-PATH." (mlet %store-monad ((set-load-path (load-path-expression (gexp-modules exp) module-path #:extensions - (gexp-extensions exp)))) + (gexp-extensions exp) + #:system system + #:target target))) (gexp->derivation name (gexp (call-with-output-file (ungexp output) @@ -1572,6 +1581,8 @@ imported modules in its search path. Look up EXP's modules in MODULE-PATH." (write '(ungexp exp) port) (chmod port #o555)))) + #:system system + #:target target #:module-path module-path))) (define* (gexp->file name exp #:key diff --git a/tests/gexp.scm b/tests/gexp.scm index 460afe7f59..5c013d838d 100644 --- a/tests/gexp.scm +++ b/tests/gexp.scm @@ -1104,6 +1104,25 @@ (return (and (zero? (close-pipe pipe)) (= 42 (string->number str))))))))) +(test-assertm "program-file #:system" + (let* ((exp (with-imported-modules '((guix build utils)) + (gexp (begin + (use-modules (guix build utils)) + (display "hi!"))))) + (system (if (string=? (%current-system) "x86_64-linux") + "armhf-linux" + "x86_64-linux")) + (file (program-file "program" exp))) + (mlet %store-monad ((drv (lower-object file system))) + (return (and (string=? (derivation-system drv) system) + (find (lambda (input) + (let ((drv (pk (derivation-input-derivation input)))) + (and (string=? (derivation-name drv) + "module-import-compiled") + (string=? (derivation-system drv) + system)))) + (derivation-inputs drv))))))) + (test-assertm "scheme-file" (let* ((text (plain-file "foo" "Hello, world!")) (scheme (scheme-file "bar" #~(list "foo" #$text)))) -- cgit 1.4.1