home: import: Avoid duplication of 'manifest->code'.

* guix/scripts/home/import.scm (manifest->code): Remove.
(manifest+configuration-files->code): New procedure.
(import-manifest): Use 'manifest+configuration-files->code' instead of
'manifest->code'.
* tests/home-import.scm (eval-test-with-home-environment): Likewise.
(match-home-environment-transformations): New procedure.
("manifest->code: No services, package transformations"): New test.
This commit is contained in:
Ludovic Courtès 2021-10-31 00:02:27 +02:00
parent 96728c54df
commit 6f4ca78761
No known key found for this signature in database
GPG Key ID: 090B11993D9AEBB5
2 changed files with 66 additions and 137 deletions

View File

@ -1,6 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
;;; Copyright © 2021 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@ -31,7 +32,7 @@
#:export (import-manifest
;; For tests.
manifest->code))
manifest+configuration-files->code))
;;; Commentary:
;;;
@ -105,146 +106,49 @@ in CONFIGURATION-DIRECTORY."
(map (lambda (proc) (proc configuration-directory)) configurations))
;; Based on `manifest->code' from (guix profiles)
;; MAYBE: Upstream it?
(define* (manifest->code manifest destination-directory
#:key
(entry-package-version (const ""))
(home-environment? #f))
"Return an sexp representing code to build an approximate version of
MANIFEST; the code is wrapped in a top-level 'begin' form. If
HOME-ENVIRONMENT? is #t, return an <home-environment> definition.
Call ENTRY-PACKAGE-VERSION to determine the version number to use in
the spec for a given entry; it can be set to 'manifest-entry-version'
for fully-specified version numbers, or to some other procedure to
disambiguate versions for packages for which several versions are
available."
(define (entry-transformations entry)
;; Return the transformations that apply to ENTRY.
(assoc-ref (manifest-entry-properties entry) 'transformations))
(define (manifest+configuration-files->code manifest
configuration-directory)
"Read MANIFEST and the user's configuration files listed in
%FILES+CONFIGURATIONS-ALIST, and return a 'home-environment' sexp. Copy the
user's files to CONFIGURATION-DIRECTORY; the generated sexp refers to them."
(match (manifest->code manifest
#:entry-package-version
manifest-entry-version-prefix)
(('begin ('use-modules profile-modules ...)
definitions ... ('packages->manifest packages))
(match (configurations+modules configuration-directory)
(((services . modules) ...)
`(begin
(use-modules (gnu home)
(gnu packages)
(gnu services)
,@(delete-duplicates
(append profile-modules (concatenate modules))))
(define transformation-procedures
;; List of transformation options/procedure name pairs.
(let loop ((entries (manifest-entries manifest))
(counter 1)
(result '()))
(match entries
(() result)
((entry . tail)
(match (entry-transformations entry)
(#f
(loop tail counter result))
(options
(if (assoc-ref result options)
(loop tail counter result)
(loop tail (+ 1 counter)
(alist-cons options
(string->symbol
(format #f "transform~a" counter))
result)))))))))
,@definitions
(define (qualified-name entry)
;; Return the name of ENTRY possibly with "@" followed by a version.
(match (entry-package-version entry)
("" (manifest-entry-name entry))
(version (string-append (manifest-entry-name entry)
"@" version))))
(home-environment
(packages ,packages)
(services (list ,@services)))))))
(('begin ('specifications->manifest packages))
(match (configurations+modules configuration-directory)
(((services . modules) ...)
`(begin
(use-modules (gnu home)
(gnu packages)
(gnu services)
,@(delete-duplicates (concatenate modules)))
(if (null? transformation-procedures)
(let ((specs (map (lambda (entry)
(match (manifest-entry-output entry)
("out" (qualified-name entry))
(output (string-append (qualified-name entry)
":" output))))
(manifest-entries manifest))))
(if home-environment?
(let ((configurations+modules
(configurations+modules destination-directory)))
`(begin
(use-modules (gnu home)
(gnu packages)
(gnu services)
,@((compose delete-duplicates concatenate)
(map cdr configurations+modules)))
,(home-environment-template
#:specs specs
#:services (map first configurations+modules))))
`(begin
(use-modules (gnu packages))
(specifications->manifest
(list ,@specs)))))
(let* ((transform (lambda (options exp)
(if (not options)
exp
(let ((proc (assoc-ref transformation-procedures
options)))
`(,proc ,exp)))))
(packages (map (lambda (entry)
(define options
(entry-transformations entry))
(define name
(qualified-name entry))
(match (manifest-entry-output entry)
("out"
(transform options
`(specification->package ,name)))
(output
`(list ,(transform
options
`(specification->package ,name))
,output))))
(manifest-entries manifest)))
(transformations (map (match-lambda
((options . name)
`(define ,name
(options->transformation ',options))))
transformation-procedures)))
(if home-environment?
(let ((configurations+modules
(configurations+modules destination-directory)))
`(begin
(use-modules (guix transformations)
(gnu home)
(gnu packages)
(gnu services)
,@((compose delete-duplicates concatenate)
(map cdr configurations+modules)))
,@transformations
,(home-environment-template
#:packages packages
#:services (map first configurations+modules))))
`(begin
(use-modules (guix transformations)
(gnu packages))
,@transformations
(packages->manifest
(list ,@packages)))))))
(define* (home-environment-template #:key (packages #f) (specs #f) services)
"Return an S-exp containing a <home-environment> declaration
containing PACKAGES, or SPECS (package specifications), and SERVICES."
`(home-environment
(packages
,@(if packages
`((list ,@packages))
`((map specification->package
(list ,@specs)))))
(services (list ,@services))))
(home-environment
(packages (map specification->package ,packages))
(services (list ,@services)))))))))
(define* (import-manifest
manifest destination-directory
#:optional (port (current-output-port)))
"Write to PORT a <home-environment> corresponding to MANIFEST."
(match (manifest->code manifest destination-directory
#:entry-package-version manifest-entry-version-prefix
#:home-environment? #t)
(match (manifest+configuration-files->code manifest
destination-directory)
(('begin exp ...)
(format port (G_ "\
;; This \"home-environment\" file can be passed to 'guix home reconfigure'

View File

@ -87,10 +87,8 @@ corresponding file."
(create-temporary-home files-alist)
(setenv "HOME" %temporary-home-directory)
(mkdir-p %temporary-home-directory)
(let* ((home-environment (manifest->code manifest %destination-directory
#:entry-package-version
manifest-entry-version-prefix
#:home-environment? #t))
(let* ((home-environment (manifest+configuration-files->code
manifest %destination-directory))
(result (matcher home-environment)))
(delete-file-recursively %temporary-home-directory)
result))
@ -108,6 +106,22 @@ corresponding file."
('services
('list)))))
(define-home-environment-matcher match-home-environment-transformations
('begin
('use-modules
('gnu 'home)
('gnu 'packages)
('gnu 'services)
('guix 'transformations))
('define transform ('options->transformation _))
('home-environment
('packages
('list (transform ('specification->package "guile@2.0.9"))
('specification->package "gcc")
('specification->package "glibc@2.19")))
('services ('list)))))
(define-home-environment-matcher match-home-environment-no-services-nor-packages
('begin
('use-modules
@ -141,12 +155,23 @@ corresponding file."
('list ('local-file "/tmp/guix-config/.bashrc"
"bashrc"))))))))))
(test-assert "manifest->code: No services"
(eval-test-with-home-environment
'()
(make-manifest (list guile-2.0.9 gcc glibc))
match-home-environment-no-services))
(test-assert "manifest->code: No services, package transformations"
(eval-test-with-home-environment
'()
(make-manifest (list (manifest-entry
(inherit guile-2.0.9)
(properties `((transformations
. ((foo . "bar"))))))
gcc glibc))
match-home-environment-transformations))
(test-assert "manifest->code: No packages nor services"
(eval-test-with-home-environment
'()