diff mbox series

[bug#43064] gexp: computed-file: Prevent mistakenly overriding default option values.

Message ID 20200827051226.28117-1-maxim.cournoyer@gmail.com
State Accepted
Headers show
Series [bug#43064] gexp: computed-file: Prevent mistakenly overriding default option values. | expand

Checks

Context Check Description
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch success View Laminar job

Commit Message

Maxim Cournoyer Aug. 27, 2020, 5:12 a.m. UTC
Because the options are passed as a list rather than actual keyword arguments,
omitting to repeat the default values in that list easily causes the default
values to be lost.

* guix/gexp.scm (%computed-file-default-options): New variable.
(alist->plist): New procedure.
(computed-file-combine-options-with-defaults): New procedure.
(computed-file): Use the above procedures to form the default OPTIONS value.
Update doc.  Use the COMPUTED-FILE-COMBINE-OPTIONS-WITH-DEFAULTS procedure to
combine the user options with the default options, when they aren't
overridden.
* tests/gexp.scm ("computed-file options defaults honored")
("computed-file options defaults overridden"): Add tests.
---
 guix/gexp.scm  | 42 +++++++++++++++++++++++++++++++++++++++---
 tests/gexp.scm | 12 ++++++++++++
 2 files changed, 51 insertions(+), 3 deletions(-)

Comments

Ludovic Courtès Aug. 30, 2020, 7:41 p.m. UTC | #1
Hi,

Maxim Cournoyer <maxim.cournoyer@gmail.com> skribis:

> Because the options are passed as a list rather than actual keyword arguments,
> omitting to repeat the default values in that list easily causes the default
> values to be lost.
>
> * guix/gexp.scm (%computed-file-default-options): New variable.
> (alist->plist): New procedure.
> (computed-file-combine-options-with-defaults): New procedure.
> (computed-file): Use the above procedures to form the default OPTIONS value.
> Update doc.  Use the COMPUTED-FILE-COMBINE-OPTIONS-WITH-DEFAULTS procedure to
> combine the user options with the default options, when they aren't
> overridden.
> * tests/gexp.scm ("computed-file options defaults honored")
> ("computed-file options defaults overridden"): Add tests.

How about exposing some of the relevant options as keywords?  We can
keep #:options as an “escape hatch” and add things like like
#:local-build? etc.  That would be simpler and more idiomatic.

Thanks,
Ludo’.
diff mbox series

Patch

diff --git a/guix/gexp.scm b/guix/gexp.scm
index 67b6121313..14e07e8fe6 100644
--- a/guix/gexp.scm
+++ b/guix/gexp.scm
@@ -3,6 +3,7 @@ 
 ;;; Copyright © 2018 Clément Lassieur <clement@lassieur.org>
 ;;; Copyright © 2018 Jan Nieuwenhuizen <janneke@gnu.org>
 ;;; Copyright © 2019, 2020 Mathieu Othacehe <m.othacehe@gmail.com>
+;;; Copyright © 2020 Maxim Cournoyer <maxim.cournoyer@gmail.com>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -503,14 +504,49 @@  This is the declarative counterpart of 'text-file'."
   (guile      computed-file-guile)                ;<package>
   (options    computed-file-options))             ;list of arguments
 
+;;; Alist containing the default options for computed-file.
+(define %computed-file-default-options '((#:local-build? . #t)))
+
+(define (alist->plist alist)
+  "Transform an association list into a property list."
+  (fold (lambda (current acc)
+          (match current
+            ((x . y)
+             (append acc (list x y)))))
+        '()
+        alist))
+
+(define (computed-file-combine-options-with-defaults options)
+
+  (define alist->keys
+    (match-lambda
+      (((key . value) ...)
+       key)))
+
+  (define (plist->keys plist)
+    (filter keyword? plist))
+
+  (define (default-keys->plist keys)
+    (append-map (lambda (key)
+                  (list key (assq-ref %computed-file-default-options key)))
+                keys))
+
+  (let ((default-keys (lset-difference
+                       eq?
+                       (alist->keys %computed-file-default-options)
+                       (plist->keys options))))
+    (append options (default-keys->plist default-keys))))
+
 (define* (computed-file name gexp
-                        #:key guile (options '(#:local-build? #t)))
+                        #:key guile (options (alist->plist
+                                              %computed-file-default-options)))
   "Return an object representing the store item NAME, a file or directory
 computed by GEXP.  OPTIONS is a list of additional arguments to pass
-to 'gexp->derivation'.
+to 'gexp->derivation', which defaults to %COMPUTED-FILE-DEFAULT-OPTIONS.
 
 This is the declarative counterpart of 'gexp->derivation'."
-  (%computed-file name gexp guile options))
+  (let ((options* (computed-file-combine-options-with-defaults options)))
+    (%computed-file name gexp guile options*)))
 
 (define-gexp-compiler (computed-file-compiler (file <computed-file>)
                                               system target)
diff --git a/tests/gexp.scm b/tests/gexp.scm
index 1beeb67c21..350065b58d 100644
--- a/tests/gexp.scm
+++ b/tests/gexp.scm
@@ -1,5 +1,6 @@ 
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2020 Maxim Cournoyer <maxim.cournoyer@gmail.com>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -62,6 +63,9 @@ 
                                      #:target target)
                   #:guile-for-build (%guile-for-build)))
 
+(define computed-file-combine-options-with-defaults
+  (@@ (guix gexp) computed-file-combine-options-with-defaults))
+
 (define %extension-package
   ;; Example of a package to use when testing 'with-extensions'.
   (dummy-package "extension"
@@ -1367,6 +1371,14 @@ 
     (return (and (derivation? drv1) (derivation? drv2)
                  (store-path? item)))))
 
+(test-equal "computed-file options defaults honored"
+  '(#:substitutable? #t #:local-build? #t)
+  (computed-file-combine-options-with-defaults '(#:substitutable? #t)))
+
+(test-equal "computed-file options defaults overridden"
+  '(#:local-build? #f)
+  (computed-file-combine-options-with-defaults '(#:local-build? #f)))
+
 (test-assertm "lower-object, computed-file"
   (let* ((text     (plain-file "foo" "Hello!"))
          (exp      #~(begin