unofficial mirror of guix-patches@gnu.org 
 help / color / mirror / code / Atom feed
* [bug#60341] [PATCH Home] home: services: environment-variables: Add support for literal strings.
@ 2022-12-26 18:19 Ludovic Courtès
  2022-12-27  3:02 ` Andrew Tropin
  2023-01-08  2:29 ` [bug#60341] Thanks Trev
  0 siblings, 2 replies; 6+ messages in thread
From: Ludovic Courtès @ 2022-12-26 18:19 UTC (permalink / raw)
  To: 60341; +Cc: Ludovic Courtès

* 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’.

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





^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [bug#60341] [PATCH Home] home: services: environment-variables: Add support for literal strings.
  2022-12-26 18:19 [bug#60341] [PATCH Home] home: services: environment-variables: Add support for literal strings Ludovic Courtès
@ 2022-12-27  3:02 ` Andrew Tropin
  2023-01-03 22:52   ` Ludovic Courtès
  2023-01-08  2:29 ` [bug#60341] Thanks Trev
  1 sibling, 1 reply; 6+ messages in thread
From: Andrew Tropin @ 2022-12-27  3:02 UTC (permalink / raw)
  To: Ludovic Courtès, 60341; +Cc: Ludovic Courtès

[-- Attachment #1: Type: text/plain, Size: 8393 bytes --]

On 2022-12-26 19:19, Ludovic Courtès wrote:

> * 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.

>
> 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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [bug#60341] [PATCH Home] home: services: environment-variables: Add support for literal strings.
  2022-12-27  3:02 ` Andrew Tropin
@ 2023-01-03 22:52   ` Ludovic Courtès
  2023-01-04  5:24     ` Andrew Tropin
  0 siblings, 1 reply; 6+ messages in thread
From: Ludovic Courtès @ 2023-01-03 22:52 UTC (permalink / raw)
  To: Andrew Tropin; +Cc: 60341

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.

Ludo’.




^ permalink raw reply	[flat|nested] 6+ messages in thread

* [bug#60341] [PATCH Home] home: services: environment-variables: Add support for literal strings.
  2023-01-03 22:52   ` Ludovic Courtès
@ 2023-01-04  5:24     ` Andrew Tropin
  2023-01-05 14:18       ` bug#60341: " Ludovic Courtès
  0 siblings, 1 reply; 6+ messages in thread
From: Andrew Tropin @ 2023-01-04  5:24 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: 60341

[-- Attachment #1: Type: text/plain, Size: 1285 bytes --]

On 2023-01-03 23:52, Ludovic Courtès wrote:

> 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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* bug#60341: [PATCH Home] home: services: environment-variables: Add support for literal strings.
  2023-01-04  5:24     ` Andrew Tropin
@ 2023-01-05 14:18       ` Ludovic Courtès
  0 siblings, 0 replies; 6+ messages in thread
From: Ludovic Courtès @ 2023-01-05 14:18 UTC (permalink / raw)
  To: Andrew Tropin; +Cc: 60341-done

Andrew Tropin <andrew@trop.in> skribis:

> On 2023-01-03 23:52, Ludovic Courtès wrote:

[...]

>> 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’.




^ permalink raw reply	[flat|nested] 6+ messages in thread

* [bug#60341] Thanks
  2022-12-26 18:19 [bug#60341] [PATCH Home] home: services: environment-variables: Add support for literal strings Ludovic Courtès
  2022-12-27  3:02 ` Andrew Tropin
@ 2023-01-08  2:29 ` Trev
  1 sibling, 0 replies; 6+ messages in thread
From: Trev @ 2023-01-08  2:29 UTC (permalink / raw)
  To: 60341

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




^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2023-01-08  2:30 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-12-26 18:19 [bug#60341] [PATCH Home] home: services: environment-variables: Add support for literal strings Ludovic Courtès
2022-12-27  3:02 ` Andrew Tropin
2023-01-03 22:52   ` Ludovic Courtès
2023-01-04  5:24     ` Andrew Tropin
2023-01-05 14:18       ` bug#60341: " Ludovic Courtès
2023-01-08  2:29 ` [bug#60341] Thanks Trev

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).