[PATCH Home] home: services: environment-variables: Add support for literal strings.

  • Done
  • quality assurance status badge
Details
3 participants
  • Andrew Tropin
  • Ludovic Courtès
  • Trev
Owner
unassigned
Submitted by
Ludovic Courtès
Severity
normal
L
L
Ludovic Courtès wrote on 26 Dec 2022 19:19
(address . guix-patches@gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20221226181938.30003-1-ludo@gnu.org
* gnu/home/services.scm (<literal-string>): New record type.
(environment-variable-shell-definitions): Split 'shell-quote' into
'quote-string' and 'shell-double-quote'. Add 'shell-single-quote'.
Add clause for 'literal-string' records.
* tests/guix-home.sh: Test it.
* doc/guix.texi (Essential Home Services): Document it.
---
doc/guix.texi | 14 ++++++++++---
gnu/home/services.scm | 48 ++++++++++++++++++++++++++++++++-----------
tests/guix-home.sh | 4 +++-
3 files changed, 50 insertions(+), 16 deletions(-)

Hi!

I found that it’s occasionally useful to be able to define shell variables
with a value that is to be taken literally, without shell expansion. This
is what this patch implements.

Thoughts?

Ludo’.

Toggle diff (161 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index efd281d9b0..44361b481a 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -40972,13 +40972,15 @@ The easiest way to extend a service type, without defining a new service
type is to use the @code{simple-service} helper from @code{(gnu
services)}.
+@findex literal-string
@lisp
(simple-service 'some-useful-env-vars-service
home-environment-variables-service-type
`(("LESSHISTFILE" . "$XDG_CACHE_HOME/.lesshst")
("SHELL" . ,(file-append zsh "/bin/zsh"))
("USELESS_VAR" . #f)
- ("_JAVA_AWT_WM_NONREPARENTING" . #t)))
+ ("_JAVA_AWT_WM_NONREPARENTING" . #t)
+ ("LITERAL_VALUE" . ,(literal-string "$@{abc@}"))))
@end lisp
If you include such a service in you home environment definition, it
@@ -40986,11 +40988,17 @@ will add the following content to the @file{setup-environment} script
(which is expected to be sourced by the login shell):
@example
-export LESSHISTFILE=$XDG_CACHE_HOME/.lesshst
-export SHELL=/gnu/store/2hsg15n644f0glrcbkb1kqknmmqdar03-zsh-5.8/bin/zsh
+export LESSHISTFILE="$XDG_CACHE_HOME/.lesshst"
+export SHELL="/gnu/store/2hsg15n644f0glrcbkb1kqknmmqdar03-zsh-5.8/bin/zsh"
export _JAVA_AWT_WM_NONREPARENTING
+export LITERAL_VALUE='$@{abc@}'
@end example
+Notice that @code{literal-string} above lets us declare that a value is
+to be interpreted as a @dfn{literal string}, meaning that ``special
+characters'' such as the dollar sign will not be interpreted by the
+shell.
+
@quotation Note
Make sure that module @code{(gnu packages shells)} is imported with
@code{use-modules} or any other way, this namespace contains the
diff --git a/gnu/home/services.scm b/gnu/home/services.scm
index 99035686f1..2c1f58fddf 100644
--- a/gnu/home/services.scm
+++ b/gnu/home/services.scm
@@ -1,6 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
+;;; Copyright © 2022 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -33,6 +34,7 @@ (define-module (gnu home services)
#:use-module (guix i18n)
#:use-module (guix modules)
#:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-9)
#:use-module (ice-9 match)
#:use-module (ice-9 vlist)
@@ -47,6 +49,10 @@ (define-module (gnu home services)
home-run-on-change-service-type
home-provenance-service-type
+ literal-string
+ literal-string?
+ literal-string-value
+
environment-variable-shell-definitions
home-files-directory
xdg-configuration-files-directory
@@ -171,32 +177,50 @@ (define home-profile-service-type
configuration files that the user has declared in their
@code{home-environment} record.")))
+;; Representation of a literal string.
+(define-record-type <literal-string>
+ (literal-string str)
+ literal-string?
+ (str literal-string-value))
+
(define (environment-variable-shell-definitions variables)
"Return a gexp that evaluates to a list of POSIX shell statements defining
VARIABLES, a list of environment variable name/value pairs. The returned code
ensures variable values are properly quoted."
- #~(let ((shell-quote
- (lambda (value)
- ;; Double-quote VALUE, leaving dollar sign as is.
- (let ((quoted (list->string
- (string-fold-right
+ #~(let* ((quote-string
+ (lambda (value quoted-chars)
+ (list->string (string-fold-right
(lambda (chr lst)
- (case chr
- ((#\" #\\)
- (append (list chr #\\) lst))
- (else (cons chr lst))))
+ (if (memq chr quoted-chars)
+ (append (list chr #\\) lst)
+ (cons chr lst)))
'()
value))))
- (string-append "\"" quoted "\"")))))
+ (shell-double-quote
+ (lambda (value)
+ ;; Double-quote VALUE, leaving dollar sign as is.
+ (string-append "\"" (quote-string value '(#\" #\\))
+ "\"")))
+ (shell-single-quote
+ (lambda (value)
+ ;; Single-quote VALUE to enter a literal string.
+ (string-append "'" (quote-string value '(#\' #\\))
+ "'"))))
(string-append
#$@(map (match-lambda
((key . #f)
"")
((key . #t)
#~(string-append "export " #$key "\n"))
- ((key . value)
+ ((key . (? string? value))
#~(string-append "export " #$key "="
- (shell-quote #$value) "\n")))
+ (shell-double-quote #$value)
+ "\n"))
+ ((key . (? literal-string? value))
+ #~(string-append "export " #$key "="
+ (shell-single-quote
+ #$(literal-string-value value))
+ "\n")))
variables))))
(define (environment-variables->setup-environment-script vars)
diff --git a/tests/guix-home.sh b/tests/guix-home.sh
index d5e2dadbb5..423ebf6f33 100644
--- a/tests/guix-home.sh
+++ b/tests/guix-home.sh
@@ -81,7 +81,8 @@ trap 'chmod -Rf +w "$test_directory"; rm -rf "$test_directory"' EXIT
(simple-service 'add-environment-variable
home-environment-variables-service-type
- '(("TODAY" . "26 messidor")))
+ `(("TODAY" . "26 messidor")
+ ("LITERAL" . ,(literal-string "${abc}"))))
(simple-service 'home-bash-service-extension-test
home-bash-service-type
@@ -149,6 +150,7 @@ EOF
grep -q "the content of ~/.config/test.conf" "${HOME}/.config/test.conf"
grep '^export PS1="\$GUIX_ENVIRONMENT λ "$' "${HOME}/.bash_profile"
( . "${HOME}/.guix-home/setup-environment"; test "$TODAY" = "26 messidor" )
+ ( . "${HOME}/.guix-home/setup-environment"; test "$LITERAL" = '${abc}' )
# This one should still be here.
grep "stay around" "$HOME/.config/random-file"

base-commit: 9369c1ccf47d9bf6f2e28a9454c1c329a2044f19
--
2.38.1
A
A
Andrew Tropin wrote on 27 Dec 2022 04:02
(name . Ludovic Courtès)(address . ludo@gnu.org)
87o7rpa6rk.fsf@trop.in
On 2022-12-26 19:19, Ludovic Courtès wrote:

Toggle quote (20 lines)
> * gnu/home/services.scm (<literal-string>): New record type.
> (environment-variable-shell-definitions): Split 'shell-quote' into
> 'quote-string' and 'shell-double-quote'. Add 'shell-single-quote'.
> Add clause for 'literal-string' records.
> * tests/guix-home.sh: Test it.
> * doc/guix.texi (Essential Home Services): Document it.
> ---
> doc/guix.texi | 14 ++++++++++---
> gnu/home/services.scm | 48 ++++++++++++++++++++++++++++++++-----------
> tests/guix-home.sh | 4 +++-
> 3 files changed, 50 insertions(+), 16 deletions(-)
>
> Hi!
>
> I found that it’s occasionally useful to be able to define shell variables
> with a value that is to be taken literally, without shell expansion. This
> is what this patch implements.
>
> Thoughts?

Hi Ludo,

the code looks good.

I'm a little conserned that one need to learn a new abstraction to
properly quote the expression instead of just using " or ' inside value
string, but we already have af4c103595a725194318f40fc5aba110772ff417 and
with the current state of the code this change looks rational and
idiomatic. Also, it makes the interface more high-level, which can be
good in some circumstances.

Toggle quote (163 lines)
>
> Ludo’.
>
> diff --git a/doc/guix.texi b/doc/guix.texi
> index efd281d9b0..44361b481a 100644
> --- a/doc/guix.texi
> +++ b/doc/guix.texi
> @@ -40972,13 +40972,15 @@ The easiest way to extend a service type, without defining a new service
> type is to use the @code{simple-service} helper from @code{(gnu
> services)}.
>
> +@findex literal-string
> @lisp
> (simple-service 'some-useful-env-vars-service
> home-environment-variables-service-type
> `(("LESSHISTFILE" . "$XDG_CACHE_HOME/.lesshst")
> ("SHELL" . ,(file-append zsh "/bin/zsh"))
> ("USELESS_VAR" . #f)
> - ("_JAVA_AWT_WM_NONREPARENTING" . #t)))
> + ("_JAVA_AWT_WM_NONREPARENTING" . #t)
> + ("LITERAL_VALUE" . ,(literal-string "$@{abc@}"))))
> @end lisp
>
> If you include such a service in you home environment definition, it
> @@ -40986,11 +40988,17 @@ will add the following content to the @file{setup-environment} script
> (which is expected to be sourced by the login shell):
>
> @example
> -export LESSHISTFILE=$XDG_CACHE_HOME/.lesshst
> -export SHELL=/gnu/store/2hsg15n644f0glrcbkb1kqknmmqdar03-zsh-5.8/bin/zsh
> +export LESSHISTFILE="$XDG_CACHE_HOME/.lesshst"
> +export SHELL="/gnu/store/2hsg15n644f0glrcbkb1kqknmmqdar03-zsh-5.8/bin/zsh"
> export _JAVA_AWT_WM_NONREPARENTING
> +export LITERAL_VALUE='$@{abc@}'
> @end example
>
> +Notice that @code{literal-string} above lets us declare that a value is
> +to be interpreted as a @dfn{literal string}, meaning that ``special
> +characters'' such as the dollar sign will not be interpreted by the
> +shell.
> +
> @quotation Note
> Make sure that module @code{(gnu packages shells)} is imported with
> @code{use-modules} or any other way, this namespace contains the
> diff --git a/gnu/home/services.scm b/gnu/home/services.scm
> index 99035686f1..2c1f58fddf 100644
> --- a/gnu/home/services.scm
> +++ b/gnu/home/services.scm
> @@ -1,6 +1,7 @@
> ;;; GNU Guix --- Functional package management for GNU
> ;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
> ;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
> +;;; Copyright © 2022 Ludovic Courtès <ludo@gnu.org>
> ;;;
> ;;; This file is part of GNU Guix.
> ;;;
> @@ -33,6 +34,7 @@ (define-module (gnu home services)
> #:use-module (guix i18n)
> #:use-module (guix modules)
> #:use-module (srfi srfi-1)
> + #:use-module (srfi srfi-9)
> #:use-module (ice-9 match)
> #:use-module (ice-9 vlist)
>
> @@ -47,6 +49,10 @@ (define-module (gnu home services)
> home-run-on-change-service-type
> home-provenance-service-type
>
> + literal-string
> + literal-string?
> + literal-string-value
> +
> environment-variable-shell-definitions
> home-files-directory
> xdg-configuration-files-directory
> @@ -171,32 +177,50 @@ (define home-profile-service-type
> configuration files that the user has declared in their
> @code{home-environment} record.")))
>
> +;; Representation of a literal string.
> +(define-record-type <literal-string>
> + (literal-string str)
> + literal-string?
> + (str literal-string-value))
> +
> (define (environment-variable-shell-definitions variables)
> "Return a gexp that evaluates to a list of POSIX shell statements defining
> VARIABLES, a list of environment variable name/value pairs. The returned code
> ensures variable values are properly quoted."
> - #~(let ((shell-quote
> - (lambda (value)
> - ;; Double-quote VALUE, leaving dollar sign as is.
> - (let ((quoted (list->string
> - (string-fold-right
> + #~(let* ((quote-string
> + (lambda (value quoted-chars)
> + (list->string (string-fold-right
> (lambda (chr lst)
> - (case chr
> - ((#\" #\\)
> - (append (list chr #\\) lst))
> - (else (cons chr lst))))
> + (if (memq chr quoted-chars)
> + (append (list chr #\\) lst)
> + (cons chr lst)))
> '()
> value))))
> - (string-append "\"" quoted "\"")))))
> + (shell-double-quote
> + (lambda (value)
> + ;; Double-quote VALUE, leaving dollar sign as is.
> + (string-append "\"" (quote-string value '(#\" #\\))
> + "\"")))
> + (shell-single-quote
> + (lambda (value)
> + ;; Single-quote VALUE to enter a literal string.
> + (string-append "'" (quote-string value '(#\' #\\))
> + "'"))))
> (string-append
> #$@(map (match-lambda
> ((key . #f)
> "")
> ((key . #t)
> #~(string-append "export " #$key "\n"))
> - ((key . value)
> + ((key . (? string? value))
> #~(string-append "export " #$key "="
> - (shell-quote #$value) "\n")))
> + (shell-double-quote #$value)
> + "\n"))
> + ((key . (? literal-string? value))
> + #~(string-append "export " #$key "="
> + (shell-single-quote
> + #$(literal-string-value value))
> + "\n")))
> variables))))
>
> (define (environment-variables->setup-environment-script vars)
> diff --git a/tests/guix-home.sh b/tests/guix-home.sh
> index d5e2dadbb5..423ebf6f33 100644
> --- a/tests/guix-home.sh
> +++ b/tests/guix-home.sh
> @@ -81,7 +81,8 @@ trap 'chmod -Rf +w "$test_directory"; rm -rf "$test_directory"' EXIT
>
> (simple-service 'add-environment-variable
> home-environment-variables-service-type
> - '(("TODAY" . "26 messidor")))
> + `(("TODAY" . "26 messidor")
> + ("LITERAL" . ,(literal-string "${abc}"))))
>
> (simple-service 'home-bash-service-extension-test
> home-bash-service-type
> @@ -149,6 +150,7 @@ EOF
> grep -q "the content of ~/.config/test.conf" "${HOME}/.config/test.conf"
> grep '^export PS1="\$GUIX_ENVIRONMENT λ "$' "${HOME}/.bash_profile"
> ( . "${HOME}/.guix-home/setup-environment"; test "$TODAY" = "26 messidor" )
> + ( . "${HOME}/.guix-home/setup-environment"; test "$LITERAL" = '${abc}' )
>
> # This one should still be here.
> grep "stay around" "$HOME/.config/random-file"
>
> base-commit: 9369c1ccf47d9bf6f2e28a9454c1c329a2044f19

--
Best regards,
Andrew Tropin
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmOqYEAACgkQIgjSCVjB
3rB92g//fS9bqqHpP4ir7JRQqe6s6VcepQF/IKlJ17cWUz5XqnUDn0pL68bR//kv
W1k+YuTypleEkTFZRG/ZZCTlwVDRc4e6CujbrJypmghD7MSyjsLgVUr9PNsysQ2m
Kd6EUP+/jbYvR3Mfo9AT9nTWn3UFvX13Y2XHdHHGBSaNgGvrKlwz7myg0RJcC6EI
t6lz+H43y6IZeaDZ2LYEc4Wg5lM2KwU5Jcc0TCQ28KCVrjMjkMcd0gZvtEleHny6
mqydf2EujOabmNix0J7GXezRVDEOWNPlnBgCjYVMdq7DczYnRJUly8CfTOWprc0F
UT20yicG0tp+3hVcabdF0a16rL2TgzNrDU48s/2awrctUyDm1PbkyzNvzirwwMpT
s/ylsIM5kn3Wo/Kv5v3SVvT23IFuSUOylrfKX7XSPIqoBkucvNR0TskYJgglSEjs
4K5YsmLPoGsxMSkIDNcJPkOmVqoEhyiPLhRLTEzv9khbMRyADSDU4CnpNv4iKqNZ
Z0QwhButIHJv4Q9SXPIX/TdOfbr22HfeB6cbcUdF3YkCKFwYf8YcLIXpjJ+sW9It
qhN8TvkjfZHCSIPHDaZV73j7lzRzKkjUPQXiPHkKzgoHcZL8d5JRl8hF5LqfPd/q
siSZ45hcWtACH+YeBtsHcT9QwKncA6agbCnJ9EOZRY/5V7BYDt4=
=ikw6
-----END PGP SIGNATURE-----

L
L
Ludovic Courtès wrote on 3 Jan 2023 23:52
Re: bug#60341: [PATCH Home] home: services: environment-variables: Add support for literal strings.
(name . Andrew Tropin)(address . andrew@trop.in)(address . 60341@debbugs.gnu.org)
871qob6xj7.fsf_-_@gnu.org
Hi,

Andrew Tropin <andrew@trop.in> skribis:

Toggle quote (2 lines)
> On 2022-12-26 19:19, Ludovic Courtès wrote:

[...]

Toggle quote (17 lines)
>> I found that it’s occasionally useful to be able to define shell variables
>> with a value that is to be taken literally, without shell expansion. This
>> is what this patch implements.
>>
>> Thoughts?
>
> Hi Ludo,
>
> the code looks good.
>
> I'm a little conserned that one need to learn a new abstraction to
> properly quote the expression instead of just using " or ' inside value
> string, but we already have af4c103595a725194318f40fc5aba110772ff417 and
> with the current state of the code this change looks rational and
> idiomatic. Also, it makes the interface more high-level, which can be
> good in some circumstances.

Yeah, the shell/Scheme mixture is a bit weird; it’s sort of in-between
because you can’t completely ignore that it’s shell code under the hood.

Looking at https://issues.guix.gnu.org/54469, I think we should strive
to not generate non-working shell snippets. Automatic quoting and this
‘literal-string’ construct are a way to achieve that.

Ludo’.
A
A
Andrew Tropin wrote on 4 Jan 2023 06:24
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 60341@debbugs.gnu.org)
874jt6c1nc.fsf@trop.in
On 2023-01-03 23:52, Ludovic Courtès wrote:

Toggle quote (32 lines)
> Hi,
>
> Andrew Tropin <andrew@trop.in> skribis:
>
>> On 2022-12-26 19:19, Ludovic Courtès wrote:
>
> [...]
>
>>> I found that it’s occasionally useful to be able to define shell variables
>>> with a value that is to be taken literally, without shell expansion. This
>>> is what this patch implements.
>>>
>>> Thoughts?
>>
>> Hi Ludo,
>>
>> the code looks good.
>>
>> I'm a little conserned that one need to learn a new abstraction to
>> properly quote the expression instead of just using " or ' inside value
>> string, but we already have af4c103595a725194318f40fc5aba110772ff417 and
>> with the current state of the code this change looks rational and
>> idiomatic. Also, it makes the interface more high-level, which can be
>> good in some circumstances.
>
> Yeah, the shell/Scheme mixture is a bit weird; it’s sort of in-between
> because you can’t completely ignore that it’s shell code under the hood.
>
> Looking at <https://issues.guix.gnu.org/54469>, I think we should strive
> to not generate non-working shell snippets. Automatic quoting and this
> ‘literal-string’ construct are a way to achieve that.

Yep, I think this is a way to go.

--
Best regards,
Andrew Tropin
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmO1DacACgkQIgjSCVjB
3rAtaA/+OyZlFHlMBE/anUfmGxS+nbwAA+DbnS4iZF0d4cOPBEbKE0fXF+mg8sxG
cicet9x8W3H5PY7017sku1PczQ0Z/EYmrEkN1vMXxCLtZwGWzGW20w1fV0QFBUuU
yedFt9YhO/v81BvX5B+nT6ySJXQgmvkEGlB4nE9+k7zc5mN+0SedXnXLz7+7yeJr
OL4OCoxLRzaeR+7Wk2pVtNBg06RftCWcFED7MQCSLFpwskVRhcZy+JDssWBGGaXc
Wh6ANnKxiN14UGT6L2bslKMCubanfTXcfccZeL4KKMt2V+B4fvTTiAsAmSecvagg
pAoxaXwm0s6S7Wqpd+YkWoWHfzItrDMFWdmQlcMrJ/fiSz2cucgF7feQD4m8v0HC
w6LCkyu93enHpLBoLOIVBjNvu214rxc43DODKAJzjfil5JttIm0SfUwtK7Zw/Rs9
90jBdZu8c1LycxUqLKUTqWRoDpsw66wKK4cFGAiOpMs5moFN66idrW4tBtQe/WiE
6xtaghFs4z0LkM+A+FCLKLUNZboOvxQUKagLQ8sB0OOoehhi/OwqWlfc1XAmhTk1
0YF1KK3C6kF5bWiGikPN+8/VxWz52JF6GrS5cvcanZVFRJTaxr9LmmhWt3LnDBD8
FJ6JX7BSBKUHNrkD5ICMyDdlnytTRrMCxPYM5arSTBZIHUrEP1g=
=GoBM
-----END PGP SIGNATURE-----

L
L
Ludovic Courtès wrote on 5 Jan 2023 15:18
(name . Andrew Tropin)(address . andrew@trop.in)(address . 60341-done@debbugs.gnu.org)
87zgax2hfi.fsf_-_@gnu.org
Andrew Tropin <andrew@trop.in> skribis:

Toggle quote (2 lines)
> On 2023-01-03 23:52, Ludovic Courtès wrote:

[...]

Toggle quote (9 lines)
>> Yeah, the shell/Scheme mixture is a bit weird; it’s sort of in-between
>> because you can’t completely ignore that it’s shell code under the hood.
>>
>> Looking at <https://issues.guix.gnu.org/54469>, I think we should strive
>> to not generate non-working shell snippets. Automatic quoting and this
>> ‘literal-string’ construct are a way to achieve that.
>
> Yep, I think this is a way to go.

Alright, pushed as 73684dc90e013f2f0cca1097b0c944bb9aa88709.

Thanks!

Ludo’.
Closed
T
Thanks
(address . 60341@debbugs.gnu.org)
20230108022932.koiszub7tzifvwae@guix
I always knew my `environment-variables` were a mess. This patch broke
my guix home config and send me down a confusing rabbit hole to this
submission. My environment-variables form looks so nice now ;P

--

Trev : 0FB7 D06B 4A2A F07E AD5B 1169 183B 6306 8AA1 D206
?