[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

Debbugs page

Ludovic Courtès wrote 2 years ago
(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
Andrew Tropin wrote 2 years ago
(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-----

Ludovic Courtès wrote 2 years ago
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’.
Andrew Tropin wrote 2 years ago
(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-----

Ludovic Courtès wrote 2 years ago
(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
Trev wrote 2 years ago
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
?
Your comment

This issue is archived.

To comment on this conversation send an email to 60341@debbugs.gnu.org

To respond to this issue using the mumi CLI, first switch to it
mumi current 60341
Then, you may apply the latest patchset in this issue (with sign off)
mumi am -- -s
Or, compose a reply to this issue
mumi compose
Or, send patches to this issue
mumi send-email *.patch
You may also tag this issue. See list of standard tags. For example, to set the confirmed and easy tags
mumi command -t +confirmed -t +easy
Or, remove the moreinfo tag and set the help tag
mumi command -t -moreinfo -t +help