GNU bug report logs - #41253
[PATCH] guix: add script execution to "guix repl"

Previous Next

Package: guix-patches;

Reported by: Konrad Hinsen <konrad.hinsen <at> fastmail.net>

Date: Thu, 14 May 2020 09:19:02 UTC

Severity: normal

Tags: patch

Done: Ludovic Courtès <ludo <at> gnu.org>

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 41253 in the body.
You can then email your comments to 41253 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Thu, 14 May 2020 09:19:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Konrad Hinsen <konrad.hinsen <at> fastmail.net>:
New bug report received and forwarded. Copy sent to guix-patches <at> gnu.org. (Thu, 14 May 2020 09:19:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
To: guix-patches <at> gnu.org
Subject: [PATCH] guix: add script execution to "guix repl"
Date: Thu, 14 May 2020 11:18:43 +0200
* guix/scripts/repl.scm: Add filename options for script execution.
* doc/guix.texi: Document script execution by "guix repl"
---
 doc/guix.texi         | 38 +++++++++++++++-----
 guix/scripts/repl.scm | 80 ++++++++++++++++++++++++++-----------------
 2 files changed, 78 insertions(+), 40 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index d6fbd85fde..68f1a8bba3 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -238,7 +238,7 @@ Programming Interface
 * Derivations::                 Low-level interface to package derivations.
 * The Store Monad::             Purely functional interface to the store.
 * G-Expressions::               Manipulating build expressions.
-* Invoking guix repl::          Fiddling with Guix interactively.
+* Invoking guix repl::          Programming Guix in Guile
 
 Defining Packages
 
@@ -5415,7 +5415,7 @@ package definitions.
 * Derivations::                 Low-level interface to package derivations.
 * The Store Monad::             Purely functional interface to the store.
 * G-Expressions::               Manipulating build expressions.
-* Invoking guix repl::          Fiddling with Guix interactively.
+* Invoking guix repl::          Programming Guix in Guile
 @end menu
 
 @node Package Modules
@@ -8134,12 +8134,31 @@ has an associated gexp compiler, such as a @code{<package>}.
 @node Invoking guix repl
 @section Invoking @command{guix repl}
 
-@cindex REPL, read-eval-print loop
-The @command{guix repl} command spawns a Guile @dfn{read-eval-print loop}
-(REPL) for interactive programming (@pxref{Using Guile Interactively,,, guile,
-GNU Guile Reference Manual}).  Compared to just launching the @command{guile}
+@cindex REPL, read-eval-print loop, script
+The @command{guix repl} command makes it easier to program Guix in Guile
+by launching a Guile @dfn{read-eval-print loop} (REPL) for interactive
+programming (@pxref{Using Guile Interactively,,, guile,
+GNU Guile Reference Manual}), or by running Guile scripts
+(@pxref{Running Guile Scripts,,, guile,
+GNU Guile Reference Manual}).
+Compared to just launching the @command{guile}
 command, @command{guix repl} guarantees that all the Guix modules and all its
-dependencies are available in the search path.  You can use it this way:
+dependencies are available in the search path.
+
+The general syntax is:
+
+@example
+guix repl @var{options} @var{files}
+@end example
+
+When at least one @var{files} argument is provided, @var{files} are
+executed as Guile scripts in the given order:
+
+@example
+$ guix repl my-script.scm
+@end example
+
+Otherwise a Guile REPL is started:
 
 @example
 $ guix repl
@@ -8188,11 +8207,12 @@ Add @var{directory} to the front of the package module search path
 (@pxref{Package Modules}).
 
 This allows users to define their own packages and make them visible to
-the command-line tool.
+the scripts or REPL.
 
 @item -q
 Inhibit loading of the @file{~/.guile} file.  By default, that
-configuration file is loaded when spawning a @code{guile} REPL.
+configuration file is loaded when executing scripts or spawning
+a @code{guile} REPL.
 @end table
 
 @c *********************************************************************
diff --git a/guix/scripts/repl.scm b/guix/scripts/repl.scm
index ff1f208894..f4cb744bbd 100644
--- a/guix/scripts/repl.scm
+++ b/guix/scripts/repl.scm
@@ -1,6 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2018, 2019, 2020 Ludovic Courtès <ludo <at> gnu.org>
 ;;; Copyright © 2020 Simon Tournier <zimon.toutoune <at> gmail.com>
+;;; Copyright © 2020 Konrad Hinsen <konrad.hinsen <at> fastmail.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -32,10 +33,12 @@
 
 ;;; Commentary:
 ;;;
-;;; This command provides a Guile REPL
+;;; This command provides a Guile script runner and REPL in an environment
+;;; that contains all the modules comprising Guix.
 
 (define %default-options
-  `((type . guile)))
+  `((scripts . ())
+    (type . guile)))
 
 (define %options
   (list (option '(#\h "help") #f #f
@@ -63,8 +66,9 @@
 
 
 (define (show-help)
-  (display (G_ "Usage: guix repl [OPTIONS...]
-Start a Guile REPL in the Guix execution environment.\n"))
+  (display (G_ "Usage: guix repl [OPTIONS...] [FILES...]
+In the Guix execution environment, run FILES as Guile scripts,
+or start a Guile REPL if no FILES are given,\n"))
   (display (G_ "
   -t, --type=TYPE        start a REPL of the given TYPE"))
   (display (G_ "
@@ -135,12 +139,13 @@ call THUNK."
 
 (define (guix-repl . args)
   (define opts
-    ;; Return the list of package names.
     (args-fold* args %options
                 (lambda (opt name arg result)
                   (leave (G_ "~A: unrecognized option~%") name))
                 (lambda (arg result)
-                  (leave (G_ "~A: extraneous argument~%") arg))
+                  (alist-cons 'scripts
+                              (cons arg (cdr (assq 'scripts result)))
+                              result))
                 %default-options))
 
   (define user-config
@@ -148,29 +153,42 @@ call THUNK."
            (lambda (home)
              (string-append home "/.guile"))))
 
+  (define (set-user-module)
+    (set-current-module user-module)
+    (when (and (not (assoc-ref opts 'ignore-dot-guile?))
+               user-config
+               (file-exists? user-config))
+      (load user-config)))
+
   (with-error-handling
-    (let ((type (assoc-ref opts 'type)))
-      (call-with-connection (assoc-ref opts 'listen)
-        (lambda ()
-          (case type
-            ((guile)
-             (save-module-excursion
-              (lambda ()
-                (set-current-module user-module)
-                (when (and (not (assoc-ref opts 'ignore-dot-guile?))
-                           user-config
-                           (file-exists? user-config))
-                  (load user-config))
-
-                ;; Do not exit repl on SIGINT.
-                ((@@ (ice-9 top-repl) call-with-sigint)
-                 (lambda ()
-                   (start-repl))))))
-            ((machine)
-             (machine-repl))
-            (else
-             (leave (G_ "~a: unknown type of REPL~%") type))))))))
-
-;; Local Variables:
-;; eval: (put 'call-with-connection 'scheme-indent-function 1)
-;; End:
+    (let ((scripts (reverse (assoc-ref opts 'scripts))))
+
+      (for-each (lambda (script)
+                  (save-module-excursion
+                   (lambda ()
+                     (set-user-module)
+                     (load script))))
+                scripts)
+
+      (when (null? scripts)
+        (let ((type (assoc-ref opts 'type)))
+          (call-with-connection (assoc-ref opts 'listen)
+            (lambda ()
+              (case type
+                ((guile)
+                 (save-module-excursion
+                  (lambda ()
+                    (set-user-module)
+                    ;; Do not exit repl on SIGINT.
+                    ((@@ (ice-9 top-repl) call-with-sigint)
+                     (lambda ()
+                       (start-repl))))))
+                ((machine)
+                 (machine-repl))
+                (else
+                 (leave (G_ "~a: unknown type of REPL~%") type)))))))))
+
+  ;; Local Variables:
+  ;; eval: (put 'call-with-connection 'scheme-indent-function 1)
+  ;; End:
+  )
-- 
2.26.2





Information forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Thu, 14 May 2020 16:27:01 GMT) Full text and rfc822 format available.

Message #8 received at 41253 <at> debbugs.gnu.org (full text, mbox):

From: zimoun <zimon.toutoune <at> gmail.com>
To: 41253 <at> debbugs.gnu.org
Cc: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
Subject: [PATCH v2] guix repl: Add script execution.
Date: Thu, 14 May 2020 18:25:37 +0200
From: Konrad Hinsen <konrad.hinsen <at> fastmail.net>

* guix/scripts/repl.scm: Add filename options for script execution.
* doc/guix.texi (Invoking guix repl): Document it.
* tests/guix-repl.sh: Test it.
---
 Makefile.am           |  1 +
 doc/guix.texi         | 38 +++++++++++++++-----
 guix/scripts/repl.scm | 80 ++++++++++++++++++++++++++-----------------
 tests/guix-repl.sh    | 70 +++++++++++++++++++++++++++++++++++++
 4 files changed, 149 insertions(+), 40 deletions(-)
 create mode 100644 tests/guix-repl.sh

diff --git a/Makefile.am b/Makefile.am
index 752445afcb..eb4e360c6d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -471,6 +471,7 @@ SH_TESTS =					\
   tests/guix-environment-container.sh		\
   tests/guix-graph.sh				\
   tests/guix-describe.sh			\
+  tests/guix-repl.sh     			\
   tests/guix-lint.sh
 
 TESTS = $(SCM_TESTS) $(SH_TESTS)
diff --git a/doc/guix.texi b/doc/guix.texi
index d6fbd85fde..68f1a8bba3 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -238,7 +238,7 @@ Programming Interface
 * Derivations::                 Low-level interface to package derivations.
 * The Store Monad::             Purely functional interface to the store.
 * G-Expressions::               Manipulating build expressions.
-* Invoking guix repl::          Fiddling with Guix interactively.
+* Invoking guix repl::          Programming Guix in Guile
 
 Defining Packages
 
@@ -5415,7 +5415,7 @@ package definitions.
 * Derivations::                 Low-level interface to package derivations.
 * The Store Monad::             Purely functional interface to the store.
 * G-Expressions::               Manipulating build expressions.
-* Invoking guix repl::          Fiddling with Guix interactively.
+* Invoking guix repl::          Programming Guix in Guile
 @end menu
 
 @node Package Modules
@@ -8134,12 +8134,31 @@ has an associated gexp compiler, such as a @code{<package>}.
 @node Invoking guix repl
 @section Invoking @command{guix repl}
 
-@cindex REPL, read-eval-print loop
-The @command{guix repl} command spawns a Guile @dfn{read-eval-print loop}
-(REPL) for interactive programming (@pxref{Using Guile Interactively,,, guile,
-GNU Guile Reference Manual}).  Compared to just launching the @command{guile}
+@cindex REPL, read-eval-print loop, script
+The @command{guix repl} command makes it easier to program Guix in Guile
+by launching a Guile @dfn{read-eval-print loop} (REPL) for interactive
+programming (@pxref{Using Guile Interactively,,, guile,
+GNU Guile Reference Manual}), or by running Guile scripts
+(@pxref{Running Guile Scripts,,, guile,
+GNU Guile Reference Manual}).
+Compared to just launching the @command{guile}
 command, @command{guix repl} guarantees that all the Guix modules and all its
-dependencies are available in the search path.  You can use it this way:
+dependencies are available in the search path.
+
+The general syntax is:
+
+@example
+guix repl @var{options} @var{files}
+@end example
+
+When at least one @var{files} argument is provided, @var{files} are
+executed as Guile scripts in the given order:
+
+@example
+$ guix repl my-script.scm
+@end example
+
+Otherwise a Guile REPL is started:
 
 @example
 $ guix repl
@@ -8188,11 +8207,12 @@ Add @var{directory} to the front of the package module search path
 (@pxref{Package Modules}).
 
 This allows users to define their own packages and make them visible to
-the command-line tool.
+the scripts or REPL.
 
 @item -q
 Inhibit loading of the @file{~/.guile} file.  By default, that
-configuration file is loaded when spawning a @code{guile} REPL.
+configuration file is loaded when executing scripts or spawning
+a @code{guile} REPL.
 @end table
 
 @c *********************************************************************
diff --git a/guix/scripts/repl.scm b/guix/scripts/repl.scm
index ff1f208894..f4cb744bbd 100644
--- a/guix/scripts/repl.scm
+++ b/guix/scripts/repl.scm
@@ -1,6 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2018, 2019, 2020 Ludovic Courtès <ludo <at> gnu.org>
 ;;; Copyright © 2020 Simon Tournier <zimon.toutoune <at> gmail.com>
+;;; Copyright © 2020 Konrad Hinsen <konrad.hinsen <at> fastmail.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -32,10 +33,12 @@
 
 ;;; Commentary:
 ;;;
-;;; This command provides a Guile REPL
+;;; This command provides a Guile script runner and REPL in an environment
+;;; that contains all the modules comprising Guix.
 
 (define %default-options
-  `((type . guile)))
+  `((scripts . ())
+    (type . guile)))
 
 (define %options
   (list (option '(#\h "help") #f #f
@@ -63,8 +66,9 @@
 
 
 (define (show-help)
-  (display (G_ "Usage: guix repl [OPTIONS...]
-Start a Guile REPL in the Guix execution environment.\n"))
+  (display (G_ "Usage: guix repl [OPTIONS...] [FILES...]
+In the Guix execution environment, run FILES as Guile scripts,
+or start a Guile REPL if no FILES are given,\n"))
   (display (G_ "
   -t, --type=TYPE        start a REPL of the given TYPE"))
   (display (G_ "
@@ -135,12 +139,13 @@ call THUNK."
 
 (define (guix-repl . args)
   (define opts
-    ;; Return the list of package names.
     (args-fold* args %options
                 (lambda (opt name arg result)
                   (leave (G_ "~A: unrecognized option~%") name))
                 (lambda (arg result)
-                  (leave (G_ "~A: extraneous argument~%") arg))
+                  (alist-cons 'scripts
+                              (cons arg (cdr (assq 'scripts result)))
+                              result))
                 %default-options))
 
   (define user-config
@@ -148,29 +153,42 @@ call THUNK."
            (lambda (home)
              (string-append home "/.guile"))))
 
+  (define (set-user-module)
+    (set-current-module user-module)
+    (when (and (not (assoc-ref opts 'ignore-dot-guile?))
+               user-config
+               (file-exists? user-config))
+      (load user-config)))
+
   (with-error-handling
-    (let ((type (assoc-ref opts 'type)))
-      (call-with-connection (assoc-ref opts 'listen)
-        (lambda ()
-          (case type
-            ((guile)
-             (save-module-excursion
-              (lambda ()
-                (set-current-module user-module)
-                (when (and (not (assoc-ref opts 'ignore-dot-guile?))
-                           user-config
-                           (file-exists? user-config))
-                  (load user-config))
-
-                ;; Do not exit repl on SIGINT.
-                ((@@ (ice-9 top-repl) call-with-sigint)
-                 (lambda ()
-                   (start-repl))))))
-            ((machine)
-             (machine-repl))
-            (else
-             (leave (G_ "~a: unknown type of REPL~%") type))))))))
-
-;; Local Variables:
-;; eval: (put 'call-with-connection 'scheme-indent-function 1)
-;; End:
+    (let ((scripts (reverse (assoc-ref opts 'scripts))))
+
+      (for-each (lambda (script)
+                  (save-module-excursion
+                   (lambda ()
+                     (set-user-module)
+                     (load script))))
+                scripts)
+
+      (when (null? scripts)
+        (let ((type (assoc-ref opts 'type)))
+          (call-with-connection (assoc-ref opts 'listen)
+            (lambda ()
+              (case type
+                ((guile)
+                 (save-module-excursion
+                  (lambda ()
+                    (set-user-module)
+                    ;; Do not exit repl on SIGINT.
+                    ((@@ (ice-9 top-repl) call-with-sigint)
+                     (lambda ()
+                       (start-repl))))))
+                ((machine)
+                 (machine-repl))
+                (else
+                 (leave (G_ "~a: unknown type of REPL~%") type)))))))))
+
+  ;; Local Variables:
+  ;; eval: (put 'call-with-connection 'scheme-indent-function 1)
+  ;; End:
+  )
diff --git a/tests/guix-repl.sh b/tests/guix-repl.sh
new file mode 100644
index 0000000000..b93d48248d
--- /dev/null
+++ b/tests/guix-repl.sh
@@ -0,0 +1,70 @@
+# GNU Guix --- Functional package management for GNU
+# Copyright © 2020 Simon Tournier <zimon.toutoune <at> gmail.com>
+#
+# This file is part of GNU Guix.
+#
+# GNU Guix is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or (at
+# your option) any later version.
+#
+# GNU Guix is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+#
+# Test the `guix repl' command-line utility.
+#
+
+guix repl --version
+
+test_directory="`mktemp -d`"
+export test_directory
+trap 'chmod -Rf +w "$test_directory"; rm -rf "$test_directory"' EXIT
+
+tmpfile="$test_directory/foo.scm"
+rm -f "$tmpfile"
+trap 'rm -f "$tmpfile"' EXIT
+
+module_dir="t-guix-repl-$$"
+mkdir "$module_dir"
+trap 'rm -rf "$module_dir"' EXIT
+
+
+cat > "$tmpfile"<<EOF
+(use-modules (guix packages)
+             (gnu packages base))
+
+(format #t "~a\n" (package-name coreutils))
+EOF
+
+# Inhibit loading of ~/.guile to avoid conflict
+test "`guix repl -q "$tmpfile"`" = "coreutils"
+
+
+cat > "$module_dir/foo.scm"<<EOF
+(define-module (foo)
+  #:use-module (guix packages)
+  #:use-module (gnu packages base))
+
+(define-public dummy
+  (package (inherit hello)
+    (name "dummy")
+    (version "42")
+    (synopsis "dummy package")
+    (description "dummy package. Only used for testing purposes.")))
+EOF
+
+cat > "$tmpfile"<<EOF
+(use-modules (guix packages)
+             (foo))
+
+(format #t "~a\n" (package-version dummy))
+EOF
+
+# Inhibit loading of ~/.guile to avoid conflict
+test "`guix repl -q "$tmpfile" -L "$module_dir"`" = "42"
-- 
2.26.1





Information forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Thu, 14 May 2020 16:32:02 GMT) Full text and rfc822 format available.

Message #11 received at 41253 <at> debbugs.gnu.org (full text, mbox):

From: zimoun <zimon.toutoune <at> gmail.com>
To: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
Cc: 41253 <at> debbugs.gnu.org
Subject: Re: [bug#41253] [PATCH] guix: add script execution to "guix repl"
Date: Thu, 14 May 2020 18:31:12 +0200
Dear Konrad,

Nice!
Thank you!

On Thu, 14 May 2020 at 11:19, Konrad Hinsen <konrad.hinsen <at> fastmail.net> wrote:
>
> * guix/scripts/repl.scm: Add filename options for script execution.
> * doc/guix.texi: Document script execution by "guix repl"

I have sent a v2 adding tests and rewording the commit message -- to
be what I understand the compliance; sorry if I did a mistake.
Well, I am not sure by the tests.

Last,  I am not convinced by the @cindex term and I think "@cindex
repl, guix repl" or "@cindex REPL, guix repl" is better.  But that's
only matter of taste. :-)


All the best,
simon




Information forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Fri, 29 May 2020 10:12:02 GMT) Full text and rfc822 format available.

Message #14 received at 41253 <at> debbugs.gnu.org (full text, mbox):

From: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
To: 41253 <at> debbugs.gnu.org
Subject: [PATCH v3] guix repl: Add script execution.
Date: Fri, 29 May 2020 12:11:26 +0200
* guix/scripts/repl.scm: Add filename options for script execution.
* doc/guix.texi (Invoking guix repl): Document it.
* tests/guix-repl.sh: Test it.
---
 Makefile.am           |  1 +
 doc/guix.texi         | 45 ++++++++++++++++++-----
 guix/scripts/repl.scm | 84 ++++++++++++++++++++++++++-----------------
 tests/guix-repl.sh    | 78 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 167 insertions(+), 41 deletions(-)
 create mode 100644 tests/guix-repl.sh

diff --git a/Makefile.am b/Makefile.am
index 5b64386b53..859b6a4bc2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -473,6 +473,7 @@ SH_TESTS =					\
   tests/guix-environment-container.sh		\
   tests/guix-graph.sh				\
   tests/guix-describe.sh			\
+  tests/guix-repl.sh     			\
   tests/guix-lint.sh
 
 TESTS = $(SCM_TESTS) $(SH_TESTS)
diff --git a/doc/guix.texi b/doc/guix.texi
index 5b9942d420..aeb88a95b6 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -239,7 +239,7 @@ Programming Interface
 * Derivations::                 Low-level interface to package derivations.
 * The Store Monad::             Purely functional interface to the store.
 * G-Expressions::               Manipulating build expressions.
-* Invoking guix repl::          Fiddling with Guix interactively.
+* Invoking guix repl::          Programming Guix in Guile
 
 Defining Packages
 
@@ -5466,7 +5466,7 @@ package definitions.
 * Derivations::                 Low-level interface to package derivations.
 * The Store Monad::             Purely functional interface to the store.
 * G-Expressions::               Manipulating build expressions.
-* Invoking guix repl::          Fiddling with Guix interactively.
+* Invoking guix repl::          Programming Guix in Guile
 @end menu
 
 @node Package Modules
@@ -8240,12 +8240,38 @@ has an associated gexp compiler, such as a @code{<package>}.
 @node Invoking guix repl
 @section Invoking @command{guix repl}
 
-@cindex REPL, read-eval-print loop
-The @command{guix repl} command spawns a Guile @dfn{read-eval-print loop}
-(REPL) for interactive programming (@pxref{Using Guile Interactively,,, guile,
-GNU Guile Reference Manual}).  Compared to just launching the @command{guile}
+@cindex REPL, read-eval-print loop, script
+The @command{guix repl} command makes it easier to program Guix in Guile
+by launching a Guile @dfn{read-eval-print loop} (REPL) for interactive
+programming (@pxref{Using Guile Interactively,,, guile,
+GNU Guile Reference Manual}), or by running Guile scripts
+(@pxref{Running Guile Scripts,,, guile,
+GNU Guile Reference Manual}).
+Compared to just launching the @command{guile}
 command, @command{guix repl} guarantees that all the Guix modules and all its
-dependencies are available in the search path.  You can use it this way:
+dependencies are available in the search path.
+
+The general syntax is:
+
+@example
+guix repl @var{options} @var{files}
+@end example
+
+When at least one @var{files} argument is provided, @var{files} are
+executed as Guile scripts in the given order:
+
+@example
+$ guix repl my-script.scm
+@end example
+
+To pass arguments to the script, use @code{--} to prevent them from
+being interpreted as arguments to @command{guix repl} itself:
+
+@example
+$ guix repl -- my-script.scm --input=foo.txt
+@end example
+
+Without any filename argument, a Guile REPL is started:
 
 @example
 $ guix repl
@@ -8294,11 +8320,12 @@ Add @var{directory} to the front of the package module search path
 (@pxref{Package Modules}).
 
 This allows users to define their own packages and make them visible to
-the command-line tool.
+the script or REPL.
 
 @item -q
 Inhibit loading of the @file{~/.guile} file.  By default, that
-configuration file is loaded when spawning a @code{guile} REPL.
+configuration file is loaded when executing scripts or spawning
+a @code{guile} REPL.
 @end table
 
 @c *********************************************************************
diff --git a/guix/scripts/repl.scm b/guix/scripts/repl.scm
index ff1f208894..f8d0483ad5 100644
--- a/guix/scripts/repl.scm
+++ b/guix/scripts/repl.scm
@@ -1,6 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2018, 2019, 2020 Ludovic Courtès <ludo <at> gnu.org>
 ;;; Copyright © 2020 Simon Tournier <zimon.toutoune <at> gmail.com>
+;;; Copyright © 2020 Konrad Hinsen <konrad.hinsen <at> fastmail.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -32,10 +33,12 @@
 
 ;;; Commentary:
 ;;;
-;;; This command provides a Guile REPL
+;;; This command provides a Guile script runner and REPL in an environment
+;;; that contains all the modules comprising Guix.
 
 (define %default-options
-  `((type . guile)))
+  `((script-args . ())
+    (type . guile)))
 
 (define %options
   (list (option '(#\h "help") #f #f
@@ -63,8 +66,9 @@
 
 
 (define (show-help)
-  (display (G_ "Usage: guix repl [OPTIONS...]
-Start a Guile REPL in the Guix execution environment.\n"))
+  (display (G_ "Usage: guix repl [OPTIONS...] [-- FILE ARGS...]
+In the Guix execution environment, run FILE as a Guile script with
+command-line arguments ARGS. If no FILE is given, start a Guile REPL,\n"))
   (display (G_ "
   -t, --type=TYPE        start a REPL of the given TYPE"))
   (display (G_ "
@@ -135,42 +139,58 @@ call THUNK."
 
 (define (guix-repl . args)
   (define opts
-    ;; Return the list of package names.
     (args-fold* args %options
                 (lambda (opt name arg result)
                   (leave (G_ "~A: unrecognized option~%") name))
                 (lambda (arg result)
-                  (leave (G_ "~A: extraneous argument~%") arg))
+                  (alist-cons 'script-args
+                              (cons arg (cdr (assq 'script-args result)))
+                              result))
                 %default-options))
-
+  
   (define user-config
     (and=> (getenv "HOME")
            (lambda (home)
              (string-append home "/.guile"))))
 
+  (define (set-user-module)
+    (set-current-module user-module)
+    (when (and (not (assoc-ref opts 'ignore-dot-guile?))
+               user-config
+               (file-exists? user-config))
+      (load user-config)))
+
   (with-error-handling
-    (let ((type (assoc-ref opts 'type)))
-      (call-with-connection (assoc-ref opts 'listen)
-        (lambda ()
-          (case type
-            ((guile)
-             (save-module-excursion
-              (lambda ()
-                (set-current-module user-module)
-                (when (and (not (assoc-ref opts 'ignore-dot-guile?))
-                           user-config
-                           (file-exists? user-config))
-                  (load user-config))
-
-                ;; Do not exit repl on SIGINT.
-                ((@@ (ice-9 top-repl) call-with-sigint)
-                 (lambda ()
-                   (start-repl))))))
-            ((machine)
-             (machine-repl))
-            (else
-             (leave (G_ "~a: unknown type of REPL~%") type))))))))
-
-;; Local Variables:
-;; eval: (put 'call-with-connection 'scheme-indent-function 1)
-;; End:
+    (let ((script-args (reverse (assoc-ref opts 'script-args))))
+
+      (unless (null? script-args)
+        ;; Run script
+        (save-module-excursion
+         (lambda ()
+           (set-program-arguments script-args)
+           (set-user-module)
+           (load (car script-args)))))
+
+      (when (null? script-args)
+        ;; Start REPL
+        (let ((type (assoc-ref opts 'type)))
+          (call-with-connection (assoc-ref opts 'listen)
+            (lambda ()
+              (case type
+                ((guile)
+                 (save-module-excursion
+                  (lambda ()
+                    (set-user-module)
+                    ;; Do not exit repl on SIGINT.
+                    ((@@ (ice-9 top-repl) call-with-sigint)
+                     (lambda ()
+                       (start-repl))))))
+                ((machine)
+                 (machine-repl))
+                (else
+                 (leave (G_ "~a: unknown type of REPL~%") type)))))))))
+
+  ;; Local Variables:
+  ;; eval: (put 'call-with-connection 'scheme-indent-function 1)
+  ;; End:
+  )
diff --git a/tests/guix-repl.sh b/tests/guix-repl.sh
new file mode 100644
index 0000000000..78b775baf3
--- /dev/null
+++ b/tests/guix-repl.sh
@@ -0,0 +1,78 @@
+# GNU Guix --- Functional package management for GNU
+# Copyright © 2020 Simon Tournier <zimon.toutoune <at> gmail.com>
+# Copyright © 2020 Konrad Hinsen <konrad.hinsen <at> fastmail.net>
+#
+# This file is part of GNU Guix.
+#
+# GNU Guix is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or (at
+# your option) any later version.
+#
+# GNU Guix is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+#
+# Test the `guix repl' command-line utility.
+#
+
+guix repl --version
+
+test_directory="`mktemp -d`"
+export test_directory
+trap 'chmod -Rf +w "$test_directory"; rm -rf "$test_directory"' EXIT
+
+tmpfile="$test_directory/foo.scm"
+rm -f "$tmpfile"
+trap 'rm -f "$tmpfile"' EXIT
+
+module_dir="t-guix-repl-$$"
+mkdir "$module_dir"
+trap 'rm -rf "$module_dir"' EXIT
+
+
+cat > "$tmpfile"<<EOF
+(use-modules (guix packages)
+             (gnu packages base))
+
+(format #t "~a\n" (package-name coreutils))
+EOF
+
+# Inhibit loading of ~/.guile to avoid conflict
+test "`guix repl -q "$tmpfile"`" = "coreutils"
+
+
+cat > "$module_dir/foo.scm"<<EOF
+(define-module (foo)
+  #:use-module (guix packages)
+  #:use-module (gnu packages base))
+
+(define-public dummy
+  (package (inherit hello)
+    (name "dummy")
+    (version "42")
+    (synopsis "dummy package")
+    (description "dummy package. Only used for testing purposes.")))
+EOF
+
+cat > "$tmpfile"<<EOF
+(use-modules (guix packages)
+             (foo))
+
+(format #t "~a\n" (package-version dummy))
+EOF
+
+# Inhibit loading of ~/.guile to avoid conflict
+test "`guix repl -q "$tmpfile" -L "$module_dir"`" = "42"
+
+cat > "$tmpfile"<<EOF
+(format #t "~a\n" (cdr (command-line)))
+EOF
+
+# Inhibit loading of ~/.guile to avoid conflict
+test "`guix repl -q -- "$tmpfile" -a --input=foo.txt`" = "(-a --input=foo.txt)"
-- 
2.26.2





Information forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Fri, 29 May 2020 10:17:02 GMT) Full text and rfc822 format available.

Message #17 received at 41253 <at> debbugs.gnu.org (full text, mbox):

From: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
To: zimoun <zimon.toutoune <at> gmail.com>
Cc: 41253 <at> debbugs.gnu.org
Subject: Re: [bug#41253] [PATCH] guix: add script execution to "guix repl"
Date: Fri, 29 May 2020 12:16:17 +0200
Hi Simon,

> I have sent a v2 adding tests and rewording the commit message -- to
> be what I understand the compliance; sorry if I did a mistake.
> Well, I am not sure by the tests.

Way better than no tests!

I just submitted a v3, following a thread on help-guix
(see https://www.mail-archive.com/help-guix <at> gnu.org/msg09328.html).
The v3 patch allows

   guix repl script.scm

but also

   guix repl –  script.scm -a -b –-input=foo.txt

In exchange, only a single script can be run. This is perfectly
in line with how Guile works, but it breaks your nice interpretation
of "REPL" as applying to script execution ;-)

Cheers,
  Konrad




Information forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Fri, 29 May 2020 13:54:01 GMT) Full text and rfc822 format available.

Message #20 received at 41253 <at> debbugs.gnu.org (full text, mbox):

From: zimoun <zimon.toutoune <at> gmail.com>
To: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
Cc: 41253 <at> debbugs.gnu.org
Subject: Re: [bug#41253] [PATCH] guix: add script execution to "guix repl"
Date: Fri, 29 May 2020 15:53:38 +0200
Hi Konrad,

On Fri, 29 May 2020 at 12:16, Konrad Hinsen <konrad.hinsen <at> fastmail.net> wrote:

> I just submitted a v3, following a thread on help-guix
> (see https://www.mail-archive.com/help-guix <at> gnu.org/msg09328.html).

May I ask why this mai-archive.com instead of
lists.gnu.org/archive/html/help-guix?


> The v3 patch allows
>
>    guix repl script.scm
>
> but also
>
>    guix repl –  script.scm -a -b –-input=foo.txt

Nice!

> In exchange, only a single script can be run. This is perfectly

Do you mean that

   guix repl script_1.scm script_2.scm

does not work?


> in line with how Guile works, but it breaks your nice interpretation
> of "REPL" as applying to script execution ;-)

I can live with that. :-)


Thank you for the patch!!
Hope it will be merged soon. :-)


Cheers,
simon


ps:
Do you know why "M-x debbugs-gnu" is doing a mess with this thread?




Information forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Fri, 29 May 2020 17:23:01 GMT) Full text and rfc822 format available.

Message #23 received at 41253 <at> debbugs.gnu.org (full text, mbox):

From: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
To: zimoun <zimon.toutoune <at> gmail.com>
Cc: 41253 <at> debbugs.gnu.org
Subject: Re: [bug#41253] [PATCH] guix: add script execution to "guix repl"
Date: Fri, 29 May 2020 19:21:55 +0200
Hi Simon,

> May I ask why this mai-archive.com instead of
> lists.gnu.org/archive/html/help-guix?

Because that's what DuckDuckGo found for me. I can't remember where
all those list archives are, I just search!

>> In exchange, only a single script can be run. This is perfectly
>
> Do you mean that
>
>    guix repl script_1.scm script_2.scm
>
> does not work?

Well, it does in a way, but differently from before: it runs script₁.scm
and passes it script₂.scm as its (only) argument.

> Do you know why "M-x debbugs-gnu" is doing a mess with this thread?

No, I have never heard about "M-x debbugs-gnu". Sounds interesting
though...

Cheers,
  Konrad




Information forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Thu, 04 Jun 2020 15:07:02 GMT) Full text and rfc822 format available.

Message #26 received at 41253 <at> debbugs.gnu.org (full text, mbox):

From: Ludovic Courtès <ludo <at> gnu.org>
To: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
Cc: 41253 <at> debbugs.gnu.org, zimoun <zimon.toutoune <at> gmail.com>
Subject: Re: [bug#41253] [PATCH v3] guix repl: Add script execution.
Date: Thu, 04 Jun 2020 17:06:16 +0200
Hello!

Konrad Hinsen <konrad.hinsen <at> fastmail.net> skribis:

> * guix/scripts/repl.scm: Add filename options for script execution.
> * doc/guix.texi (Invoking guix repl): Document it.
> * tests/guix-repl.sh: Test it.

I like it!

It cannot be used as a shebang, can it?

There’s also the Makefile.am change that could be mentioned in the
commit log.

Some comments:

> +When at least one @var{files} argument is provided, @var{files} are
> +executed as Guile scripts in the given order:
> +
> +@example
> +$ guix repl my-script.scm
> +@end example
> +
> +To pass arguments to the script, use @code{--} to prevent them from
> +being interpreted as arguments to @command{guix repl} itself:
> +
> +@example
> +$ guix repl -- my-script.scm --input=foo.txt
> +@end example

I’d remove “$” from the examples.

> +Without any filename argument, a Guile REPL is started:

s/filename/file name/

>  @item -q
>  Inhibit loading of the @file{~/.guile} file.  By default, that
> -configuration file is loaded when spawning a @code{guile} REPL.
> +configuration file is loaded when executing scripts or spawning
> +a @code{guile} REPL.

I think this change is unnecessary (see below).

> +  (display (G_ "Usage: guix repl [OPTIONS...] [-- FILE ARGS...]
> +In the Guix execution environment, run FILE as a Guile script with
> +command-line arguments ARGS. If no FILE is given, start a Guile REPL,\n"))
                               ^                                       ^
Please add a space and change comma to period.

>                  (lambda (arg result)
> -                  (leave (G_ "~A: extraneous argument~%") arg))
> +                  (alist-cons 'script-args
> +                              (cons arg (cdr (assq 'script-args result)))
> +                              result))

I’d change that to just:

  (append `((script . ,arg) (ignore-dot-guile . #t)) result)

and later we can collect all the values associated with 'script.

I think “script” is clearer than “script-args” (and more in-line with
the naming conventions.)

Last but not least: I think -q should always be implied when running a
script.  ~/.guile is really meant for the REPL, nothing else.

> +  ;; Local Variables:
> +  ;; eval: (put 'call-with-connection 'scheme-indent-function 1)
> +  ;; End:
> +  )

Please move the comment to the bottom, outside the parens, as before,
otherwise this paren will feel lonely.  :-)

Thoughts?

Looks like we’re almost done.  Thank you!

Ludo’.




Information forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Fri, 05 Jun 2020 08:50:01 GMT) Full text and rfc822 format available.

Message #29 received at 41253 <at> debbugs.gnu.org (full text, mbox):

From: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
To: Ludovic Courtès <ludo <at> gnu.org>
Cc: 41253 <at> debbugs.gnu.org, zimoun <zimon.toutoune <at> gmail.com>
Subject: Re: [bug#41253] [PATCH v3] guix repl: Add script execution.
Date: Fri, 05 Jun 2020 10:48:53 +0200
Hi Ludo,

Thanks for your feedback!

> It cannot be used as a shebang, can it?

It can. And that might be worth documenting. Here's an example:

  ===== File foo.scm =========================================
  #!/usr/bin/env -S guix repl
  !#
  (use-modules (ice-9 format))

  (format #t "foo called with arguments: ~s\n"(command-line))
  ===== End of file foo.scm ==================================

  hinsen <at> guix ~$ ~/foo.scm a b c
  ;;; note: source file /home/hinsen/temp/foo.scm
  ;;;       newer than compiled /home/hinsen/.cache/guile/ccache/3.0-LE-8-4.2/home/hinsen/temp/foo.scm.go
  foo called with arguments: ("/home/hinsen/temp/foo.scm" "a" "b" "c")

The ugly part is that the script needs to be called with '–' as its
first argument if any of the following arguments start with dashes:

  hinsen <at> guix ~$ ~/foo.scm -- --help
  ;;; note: source file /home/hinsen/temp/foo.scm
  ;;;       newer than compiled /home/hinsen/.cache/guile/ccache/3.0-LE-8-4.2/home/hinsen/temp/foo.scm.go
  foo called with arguments: ("/home/hinsen/temp/foo.scm" "--help")

That could be fixed at the price of a command line interface for "guix
repl" that deviates a bit from Guix conventions. For example,
is there's a file name argument, pass all arguments following it to the
script, eliminating the need for –.

I'll try that in a v4, and also take into account all your remaining
remarks. Just one note on the examples:

>> +@example
>> +$ guix repl -- my-script.scm --input=foo.txt
>> +@end example
>
> I’d remove “$” from the examples.

There are many examples in guix.texi with $, and also many without. Plus
some with # as the command line prompt.

It makes sense to add the command line prompt for examples that also
show output, so I am not sure what the best convention is - but it would
be nice to apply a uniform style everywhere (but NOT as part of
this patch, of course).

Cheers,
  Konrad




Information forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Fri, 05 Jun 2020 10:19:02 GMT) Full text and rfc822 format available.

Message #32 received at 41253 <at> debbugs.gnu.org (full text, mbox):

From: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
To: Ludovic Courtès <ludo <at> gnu.org>
Cc: 41253 <at> debbugs.gnu.org, zimoun <zimon.toutoune <at> gmail.com>
Subject: Re: [bug#41253] [PATCH v3] guix repl: Add script execution.
Date: Fri, 05 Jun 2020 12:18:05 +0200
A technical question: is there any way to suppress the error message
about the source being newer than the cached version? This is really
annoying when running scripts.

>   hinsen <at> guix ~$ ~/foo.scm a b c
>   ;;; note: source file /home/hinsen/temp/foo.scm
>   ;;;       newer than compiled /home/hinsen/.cache/guile/ccache/3.0-LE-8-4.2/home/hinsen/temp/foo.scm.go
>   foo called with arguments: ("/home/hinsen/temp/foo.scm" "a" "b" "c")

Cheers,
  Konrad




Information forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Fri, 05 Jun 2020 16:37:02 GMT) Full text and rfc822 format available.

Message #35 received at 41253 <at> debbugs.gnu.org (full text, mbox):

From: Ludovic Courtès <ludo <at> gnu.org>
To: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
Cc: 41253 <at> debbugs.gnu.org, zimoun <zimon.toutoune <at> gmail.com>
Subject: Re: [bug#41253] [PATCH v3] guix repl: Add script execution.
Date: Fri, 05 Jun 2020 18:36:21 +0200
Hello Konrad,

Konrad Hinsen <konrad.hinsen <at> fastmail.net> skribis:

>> It cannot be used as a shebang, can it?
>
> It can. And that might be worth documenting. Here's an example:
>
>   ===== File foo.scm =========================================
>   #!/usr/bin/env -S guix repl
>   !#
>   (use-modules (ice-9 format))
>
>   (format #t "foo called with arguments: ~s\n"(command-line))
>   ===== End of file foo.scm ==================================
>
>   hinsen <at> guix ~$ ~/foo.scm a b c
>   ;;; note: source file /home/hinsen/temp/foo.scm
>   ;;;       newer than compiled /home/hinsen/.cache/guile/ccache/3.0-LE-8-4.2/home/hinsen/temp/foo.scm.go
>   foo called with arguments: ("/home/hinsen/temp/foo.scm" "a" "b" "c")

Nice!

> The ugly part is that the script needs to be called with '–' as its
> first argument if any of the following arguments start with dashes:
>
>   hinsen <at> guix ~$ ~/foo.scm -- --help
>   ;;; note: source file /home/hinsen/temp/foo.scm
>   ;;;       newer than compiled /home/hinsen/.cache/guile/ccache/3.0-LE-8-4.2/home/hinsen/temp/foo.scm.go
>   foo called with arguments: ("/home/hinsen/temp/foo.scm" "--help")
>
> That could be fixed at the price of a command line interface for "guix
> repl" that deviates a bit from Guix conventions. For example,
> is there's a file name argument, pass all arguments following it to the
> script, eliminating the need for –.

Yes, that makes sense to me.

> I'll try that in a v4, and also take into account all your remaining
> remarks. Just one note on the examples:
>
>>> +@example
>>> +$ guix repl -- my-script.scm --input=foo.txt
>>> +@end example
>>
>> I’d remove “$” from the examples.
>
> There are many examples in guix.texi with $, and also many without. Plus
> some with # as the command line prompt.

Yeah, the manual is kinda inconsistent, and I’m self-inconsistent to
tell the truth.  :-)

I’ve come to the conclusion that snippets that contain only input should
be written without a prompt, for easier copy/pasting.

(I’ve seen Python documentation where JS magic allows people to toggle
prompt display, I find it nice.)

> A technical question: is there any way to suppress the error message
> about the source being newer than the cached version? This is really
> annoying when running scripts.
>
>>   hinsen <at> guix ~$ ~/foo.scm a b c
>>   ;;; note: source file /home/hinsen/temp/foo.scm
>>   ;;;       newer than compiled /home/hinsen/.cache/guile/ccache/3.0-LE-8-4.2/home/hinsen/temp/foo.scm.go
>>   foo called with arguments: ("/home/hinsen/temp/foo.scm" "a" "b" "c")

I guess ~/.cache/…/*.go exists because you first ran “guile foo.scm”,
no?  In that case, you can simply remove that .go file.

The ‘guix’ command turns off auto-compilation so ‘guix repl’ scripts
would always be interpreted, for better or worse.

Thanks,
Ludo’.




Information forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Sat, 06 Jun 2020 05:20:01 GMT) Full text and rfc822 format available.

Message #38 received at 41253 <at> debbugs.gnu.org (full text, mbox):

From: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
To: 41253 <at> debbugs.gnu.org
Subject: [PATCH v4] guix repl: Add script execution.
Date: Sat, 06 Jun 2020 07:18:58 +0200
* guix/scripts/repl.scm: Add filename options for script execution.
* doc/guix.texi (Invoking guix repl): Document it.
* tests/guix-repl.sh: Test it.
* Makefile.am: (SH_TESTS): Add it.
---
 Makefile.am           |  1 +
 doc/guix.texi         | 51 +++++++++++++++++++++-----
 guix/scripts/repl.scm | 82 ++++++++++++++++++++++++++++--------------
 tests/guix-repl.sh    | 84 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 184 insertions(+), 34 deletions(-)
 create mode 100644 tests/guix-repl.sh

diff --git a/Makefile.am b/Makefile.am
index 5b64386b53..859b6a4bc2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -473,6 +473,7 @@ SH_TESTS =					\
   tests/guix-environment-container.sh		\
   tests/guix-graph.sh				\
   tests/guix-describe.sh			\
+  tests/guix-repl.sh     			\
   tests/guix-lint.sh
 
 TESTS = $(SCM_TESTS) $(SH_TESTS)
diff --git a/doc/guix.texi b/doc/guix.texi
index 056bf011f6..b95709d0c6 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -239,7 +239,7 @@ Programming Interface
 * Derivations::                 Low-level interface to package derivations.
 * The Store Monad::             Purely functional interface to the store.
 * G-Expressions::               Manipulating build expressions.
-* Invoking guix repl::          Fiddling with Guix interactively.
+* Invoking guix repl::          Programming Guix in Guile
 
 Defining Packages
 
@@ -5472,7 +5472,7 @@ package definitions.
 * Derivations::                 Low-level interface to package derivations.
 * The Store Monad::             Purely functional interface to the store.
 * G-Expressions::               Manipulating build expressions.
-* Invoking guix repl::          Fiddling with Guix interactively.
+* Invoking guix repl::          Programming Guix in Guile
 @end menu
 
 @node Package Modules
@@ -8246,12 +8246,47 @@ has an associated gexp compiler, such as a @code{<package>}.
 @node Invoking guix repl
 @section Invoking @command{guix repl}
 
-@cindex REPL, read-eval-print loop
-The @command{guix repl} command spawns a Guile @dfn{read-eval-print loop}
-(REPL) for interactive programming (@pxref{Using Guile Interactively,,, guile,
-GNU Guile Reference Manual}).  Compared to just launching the @command{guile}
+@cindex REPL, read-eval-print loop, script
+The @command{guix repl} command makes it easier to program Guix in Guile
+by launching a Guile @dfn{read-eval-print loop} (REPL) for interactive
+programming (@pxref{Using Guile Interactively,,, guile,
+GNU Guile Reference Manual}), or by running Guile scripts
+(@pxref{Running Guile Scripts,,, guile,
+GNU Guile Reference Manual}).
+Compared to just launching the @command{guile}
 command, @command{guix repl} guarantees that all the Guix modules and all its
-dependencies are available in the search path.  You can use it this way:
+dependencies are available in the search path.
+
+The general syntax is:
+
+@example
+guix repl @var{options} @var{file} @var{args}
+@end example
+
+When a @var{file} argument is provided, @var{file} is
+executed as a Guile scripts:
+
+@example
+guix repl my-script.scm
+@end example
+
+To pass arguments to the script, use @code{--} to prevent them from
+being interpreted as arguments to @command{guix repl} itself:
+
+@example
+guix repl -- my-script.scm --input=foo.txt
+@end example
+
+To make a script executable directly from the shell, using the guix
+executable that is on the user's search path, add the following two
+lines at the top of the script:
+
+@example
+@code{#!/usr/bin/env -S guix repl --}
+@code{!#}
+@end example
+
+Without a file name argument, a Guile REPL is started:
 
 @example
 $ guix repl
@@ -8300,7 +8335,7 @@ Add @var{directory} to the front of the package module search path
 (@pxref{Package Modules}).
 
 This allows users to define their own packages and make them visible to
-the command-line tool.
+the script or REPL.
 
 @item -q
 Inhibit loading of the @file{~/.guile} file.  By default, that
diff --git a/guix/scripts/repl.scm b/guix/scripts/repl.scm
index ff1f208894..4c2537b55d 100644
--- a/guix/scripts/repl.scm
+++ b/guix/scripts/repl.scm
@@ -1,6 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2018, 2019, 2020 Ludovic Courtès <ludo <at> gnu.org>
 ;;; Copyright © 2020 Simon Tournier <zimon.toutoune <at> gmail.com>
+;;; Copyright © 2020 Konrad Hinsen <konrad.hinsen <at> fastmail.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -22,6 +23,7 @@
   #:use-module (guix scripts)
   #:use-module (guix repl)
   #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-26)
   #:use-module (srfi srfi-37)
   #:use-module (ice-9 match)
   #:use-module (rnrs bytevectors)
@@ -32,7 +34,8 @@
 
 ;;; Commentary:
 ;;;
-;;; This command provides a Guile REPL
+;;; This command provides a Guile script runner and REPL in an environment
+;;; that contains all the modules comprising Guix.
 
 (define %default-options
   `((type . guile)))
@@ -63,8 +66,9 @@
 
 
 (define (show-help)
-  (display (G_ "Usage: guix repl [OPTIONS...]
-Start a Guile REPL in the Guix execution environment.\n"))
+  (display (G_ "Usage: guix repl [OPTIONS...] [-- FILE ARGS...]
+In the Guix execution environment, run FILE as a Guile script with
+command-line arguments ARGS.  If no FILE is given, start a Guile REPL.\n"))
   (display (G_ "
   -t, --type=TYPE        start a REPL of the given TYPE"))
   (display (G_ "
@@ -135,12 +139,13 @@ call THUNK."
 
 (define (guix-repl . args)
   (define opts
-    ;; Return the list of package names.
     (args-fold* args %options
                 (lambda (opt name arg result)
                   (leave (G_ "~A: unrecognized option~%") name))
                 (lambda (arg result)
-                  (leave (G_ "~A: extraneous argument~%") arg))
+                  (append `((script . ,arg)
+                            (ignore-dot-guile . #t))
+                          result))
                 %default-options))
 
   (define user-config
@@ -148,28 +153,53 @@ call THUNK."
            (lambda (home)
              (string-append home "/.guile"))))
 
+  (define (set-user-module)
+    (set-current-module user-module)
+    (when (and (not (assoc-ref opts 'ignore-dot-guile?))
+               user-config
+               (file-exists? user-config))
+      (load user-config)))
+
+  (define script (reverse
+                  (map cdr
+                       (filter (lambda (opt)
+                                 (eq? (car opt) 'script))
+                               opts))))
+  (define script-file
+    (let ((file (car script))
+          (directory (getcwd)))
+      (canonicalize-path
+       (cond ((string-prefix? "/" file) file)
+             (else (string-append directory "/" file))))))
+
   (with-error-handling
-    (let ((type (assoc-ref opts 'type)))
-      (call-with-connection (assoc-ref opts 'listen)
-        (lambda ()
-          (case type
-            ((guile)
-             (save-module-excursion
-              (lambda ()
-                (set-current-module user-module)
-                (when (and (not (assoc-ref opts 'ignore-dot-guile?))
-                           user-config
-                           (file-exists? user-config))
-                  (load user-config))
-
-                ;; Do not exit repl on SIGINT.
-                ((@@ (ice-9 top-repl) call-with-sigint)
-                 (lambda ()
-                   (start-repl))))))
-            ((machine)
-             (machine-repl))
-            (else
-             (leave (G_ "~a: unknown type of REPL~%") type))))))))
+
+    (unless (null? script)
+      ;; Run script
+      (save-module-excursion
+       (lambda ()
+         (set-program-arguments (cons script-file (cdr script)))
+         (set-user-module)
+         (load script-file))))
+
+    (when (null? script)
+      ;; Start REPL
+      (let ((type (assoc-ref opts 'type)))
+        (call-with-connection (assoc-ref opts 'listen)
+          (lambda ()
+            (case type
+              ((guile)
+               (save-module-excursion
+                (lambda ()
+                  (set-user-module)
+                  ;; Do not exit repl on SIGINT.
+                  ((@@ (ice-9 top-repl) call-with-sigint)
+                   (lambda ()
+                     (start-repl))))))
+              ((machine)
+               (machine-repl))
+              (else
+               (leave (G_ "~a: unknown type of REPL~%") type)))))))))
 
 ;; Local Variables:
 ;; eval: (put 'call-with-connection 'scheme-indent-function 1)
diff --git a/tests/guix-repl.sh b/tests/guix-repl.sh
new file mode 100644
index 0000000000..2750188468
--- /dev/null
+++ b/tests/guix-repl.sh
@@ -0,0 +1,84 @@
+# GNU Guix --- Functional package management for GNU
+# Copyright © 2020 Simon Tournier <zimon.toutoune <at> gmail.com>
+# Copyright © 2020 Konrad Hinsen <konrad.hinsen <at> fastmail.net>
+#
+# This file is part of GNU Guix.
+#
+# GNU Guix is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or (at
+# your option) any later version.
+#
+# GNU Guix is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+#
+# Test the `guix repl' command-line utility.
+#
+
+guix repl --version
+
+test_directory="`mktemp -d`"
+export test_directory
+trap 'chmod -Rf +w "$test_directory"; rm -rf "$test_directory"' EXIT
+
+tmpfile="$test_directory/foo.scm"
+rm -f "$tmpfile"
+trap 'rm -f "$tmpfile"' EXIT
+
+module_dir="t-guix-repl-$$"
+mkdir "$module_dir"
+trap 'rm -rf "$module_dir"' EXIT
+
+
+cat > "$tmpfile"<<EOF
+(use-modules (guix packages)
+             (gnu packages base))
+
+(format #t "~a\n" (package-name coreutils))
+EOF
+
+test "`guix repl "$tmpfile"`" = "coreutils"
+
+
+cat > "$module_dir/foo.scm"<<EOF
+(define-module (foo)
+  #:use-module (guix packages)
+  #:use-module (gnu packages base))
+
+(define-public dummy
+  (package (inherit hello)
+    (name "dummy")
+    (version "42")
+    (synopsis "dummy package")
+    (description "dummy package. Only used for testing purposes.")))
+EOF
+
+cat > "$tmpfile"<<EOF
+(use-modules (guix packages)
+             (foo))
+
+(format #t "~a\n" (package-version dummy))
+EOF
+
+test "`guix repl "$tmpfile" -L "$module_dir"`" = "42"
+
+cat > "$tmpfile"<<EOF
+(format #t "~a\n" (cdr (command-line)))
+EOF
+
+test "`guix repl -- "$tmpfile" -a b --input=foo.txt`" = "(-a b --input=foo.txt)"
+
+cat > "$tmpfile"<<EOF
+#!/usr/bin/env -S guix repl --
+!#
+(format #t "~a\n" (cdr (command-line)))
+EOF
+chmod 755 $tmpfile
+
+test "`"$tmpfile" -a b --input=foo.txt`" = "(-a b --input=foo.txt)"
-- 
2.26.2





Information forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Sat, 06 Jun 2020 05:23:02 GMT) Full text and rfc822 format available.

Message #41 received at 41253 <at> debbugs.gnu.org (full text, mbox):

From: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
To: Ludovic Courtès <ludo <at> gnu.org>
Cc: 41253 <at> debbugs.gnu.org, zimoun <zimon.toutoune <at> gmail.com>
Subject: Re: [bug#41253] [PATCH v3] guix repl: Add script execution.
Date: Sat, 06 Jun 2020 07:22:25 +0200
Hi Ludo,

Patch v4 is on its way to the world impatiently waiting for it ;-)

>> That could be fixed at the price of a command line interface for "guix
>> repl" that deviates a bit from Guix conventions. For example,
>> is there's a file name argument, pass all arguments following it to the
>> script, eliminating the need for –.
>
> Yes, that makes sense to me.

I found a much simpler solution: putting "guix repl –" on the shebang
line makes it all work. This is documented in the manual and by a
test case.

> I guess ~/.cache/…/*.go exists because you first ran “guile foo.scm”,
> no?  In that case, you can simply remove that .go file.

That did the job, thanks!

Cheers,
  Konrad.




Information forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Fri, 12 Jun 2020 15:59:01 GMT) Full text and rfc822 format available.

Message #44 received at 41253 <at> debbugs.gnu.org (full text, mbox):

From: Ludovic Courtès <ludo <at> gnu.org>
To: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
Cc: 41253 <at> debbugs.gnu.org
Subject: Re: [bug#41253] [PATCH v4] guix repl: Add script execution.
Date: Fri, 12 Jun 2020 17:58:37 +0200
Hi, and sorry for the delay!

Konrad Hinsen <konrad.hinsen <at> fastmail.net> skribis:

> * guix/scripts/repl.scm: Add filename options for script execution.
> * doc/guix.texi (Invoking guix repl): Document it.
> * tests/guix-repl.sh: Test it.
> * Makefile.am: (SH_TESTS): Add it.

I have some comments regarding style and how to deal with multiple
scripts, but I think we’re pretty much there.

> +The general syntax is:
> +
> +@example
> +guix repl @var{options} @var{file} @var{args}

Should be: [@var{file} @var{args}@dots{}]
The square brackets show it’s optional.

> +When a @var{file} argument is provided, @var{file} is
> +executed as a Guile scripts:

“When one or more @var{file} argument is provided, each @var{file} is
executed as a Guile program:”

> +  (define script (reverse
> +                  (map cdr
> +                       (filter (lambda (opt)
> +                                 (eq? (car opt) 'script))
> +                               opts))))

To avoid car/cdr (info "(guix) Data Types and Pattern Matching"), I
suggest something along these lines:

  (define scripts  ;plural, no?
    (reverse
     (filter-map (match-lambda
                   (('script . script) script)
                   (_ #f))
                 opts)))

> +  (define script-file
> +    (let ((file (car script))
> +          (directory (getcwd)))
> +      (canonicalize-path
> +       (cond ((string-prefix? "/" file) file)
> +             (else (string-append directory "/" file))))))

I think we can just use file names as they arrive, without attempting to
canonicalize them or anything.

> +    (unless (null? script)
> +      ;; Run script
> +      (save-module-excursion
> +       (lambda ()
> +         (set-program-arguments (cons script-file (cdr script)))
> +         (set-user-module)
> +         (load script-file))))

=> (for-each load scripts)
    
> +cat > "$tmpfile"<<EOF
> +#!/usr/bin/env -S guix repl --

Rather:

  #!$(type -P env)

This will ensure it works even in Guix build environments.

Could you send an updated patch?

Thank you!

Ludo’.




Information forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Sat, 13 Jun 2020 16:36:02 GMT) Full text and rfc822 format available.

Message #47 received at 41253 <at> debbugs.gnu.org (full text, mbox):

From: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
To: 41253 <at> debbugs.gnu.org
Subject: [PATCH v5] guix repl: Add script execution.
Date: Sat, 13 Jun 2020 18:34:38 +0200
* guix/scripts/repl.scm: Add filename options for script execution.
* doc/guix.texi (Invoking guix repl): Document it.
* tests/guix-repl.sh: Test it.
* Makefile.am: (SH_TESTS): Add it.
---
 Makefile.am           |  1 +
 doc/guix.texi         | 51 +++++++++++++++++++++-----
 guix/scripts/repl.scm | 84 +++++++++++++++++++++++++++++--------------
 tests/guix-repl.sh    | 84 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 186 insertions(+), 34 deletions(-)
 create mode 100644 tests/guix-repl.sh

diff --git a/Makefile.am b/Makefile.am
index 9cf9318e8a..8988cdfa12 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -477,6 +477,7 @@ SH_TESTS =					\
   tests/guix-environment-container.sh		\
   tests/guix-graph.sh				\
   tests/guix-describe.sh			\
+  tests/guix-repl.sh     			\
   tests/guix-lint.sh
 
 TESTS = $(SCM_TESTS) $(SH_TESTS)
diff --git a/doc/guix.texi b/doc/guix.texi
index 15e077a41c..8ad3a833c6 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -239,7 +239,7 @@ Programming Interface
 * Derivations::                 Low-level interface to package derivations.
 * The Store Monad::             Purely functional interface to the store.
 * G-Expressions::               Manipulating build expressions.
-* Invoking guix repl::          Fiddling with Guix interactively.
+* Invoking guix repl::          Programming Guix in Guile
 
 Defining Packages
 
@@ -5474,7 +5474,7 @@ package definitions.
 * Derivations::                 Low-level interface to package derivations.
 * The Store Monad::             Purely functional interface to the store.
 * G-Expressions::               Manipulating build expressions.
-* Invoking guix repl::          Fiddling with Guix interactively.
+* Invoking guix repl::          Programming Guix in Guile
 @end menu
 
 @node Package Modules
@@ -8248,12 +8248,47 @@ has an associated gexp compiler, such as a @code{<package>}.
 @node Invoking guix repl
 @section Invoking @command{guix repl}
 
-@cindex REPL, read-eval-print loop
-The @command{guix repl} command spawns a Guile @dfn{read-eval-print loop}
-(REPL) for interactive programming (@pxref{Using Guile Interactively,,, guile,
-GNU Guile Reference Manual}).  Compared to just launching the @command{guile}
+@cindex REPL, read-eval-print loop, script
+The @command{guix repl} command makes it easier to program Guix in Guile
+by launching a Guile @dfn{read-eval-print loop} (REPL) for interactive
+programming (@pxref{Using Guile Interactively,,, guile,
+GNU Guile Reference Manual}), or by running Guile scripts
+(@pxref{Running Guile Scripts,,, guile,
+GNU Guile Reference Manual}).
+Compared to just launching the @command{guile}
 command, @command{guix repl} guarantees that all the Guix modules and all its
-dependencies are available in the search path.  You can use it this way:
+dependencies are available in the search path.
+
+The general syntax is:
+
+@example
+guix repl @var{options} [@var{file} @var{args}]
+@end example
+
+When a @var{file} argument is provided, @var{file} is
+executed as a Guile scripts:
+
+@example
+guix repl my-script.scm
+@end example
+
+To pass arguments to the script, use @code{--} to prevent them from
+being interpreted as arguments to @command{guix repl} itself:
+
+@example
+guix repl -- my-script.scm --input=foo.txt
+@end example
+
+To make a script executable directly from the shell, using the guix
+executable that is on the user's search path, add the following two
+lines at the top of the script:
+
+@example
+@code{#!/usr/bin/env -S guix repl --}
+@code{!#}
+@end example
+
+Without a file name argument, a Guile REPL is started:
 
 @example
 $ guix repl
@@ -8302,7 +8337,7 @@ Add @var{directory} to the front of the package module search path
 (@pxref{Package Modules}).
 
 This allows users to define their own packages and make them visible to
-the command-line tool.
+the script or REPL.
 
 @item -q
 Inhibit loading of the @file{~/.guile} file.  By default, that
diff --git a/guix/scripts/repl.scm b/guix/scripts/repl.scm
index ff1f208894..51fffa278a 100644
--- a/guix/scripts/repl.scm
+++ b/guix/scripts/repl.scm
@@ -1,6 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2018, 2019, 2020 Ludovic Courtès <ludo <at> gnu.org>
 ;;; Copyright © 2020 Simon Tournier <zimon.toutoune <at> gmail.com>
+;;; Copyright © 2020 Konrad Hinsen <konrad.hinsen <at> fastmail.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -22,6 +23,7 @@
   #:use-module (guix scripts)
   #:use-module (guix repl)
   #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-26)
   #:use-module (srfi srfi-37)
   #:use-module (ice-9 match)
   #:use-module (rnrs bytevectors)
@@ -32,7 +34,8 @@
 
 ;;; Commentary:
 ;;;
-;;; This command provides a Guile REPL
+;;; This command provides a Guile script runner and REPL in an environment
+;;; that contains all the modules comprising Guix.
 
 (define %default-options
   `((type . guile)))
@@ -63,8 +66,9 @@
 
 
 (define (show-help)
-  (display (G_ "Usage: guix repl [OPTIONS...]
-Start a Guile REPL in the Guix execution environment.\n"))
+  (display (G_ "Usage: guix repl [OPTIONS...] [-- FILE ARGS...]
+In the Guix execution environment, run FILE as a Guile script with
+command-line arguments ARGS.  If no FILE is given, start a Guile REPL.\n"))
   (display (G_ "
   -t, --type=TYPE        start a REPL of the given TYPE"))
   (display (G_ "
@@ -135,12 +139,13 @@ call THUNK."
 
 (define (guix-repl . args)
   (define opts
-    ;; Return the list of package names.
     (args-fold* args %options
                 (lambda (opt name arg result)
                   (leave (G_ "~A: unrecognized option~%") name))
                 (lambda (arg result)
-                  (leave (G_ "~A: extraneous argument~%") arg))
+                  (append `((script . ,arg)
+                            (ignore-dot-guile . #t))
+                          result))
                 %default-options))
 
   (define user-config
@@ -148,28 +153,55 @@ call THUNK."
            (lambda (home)
              (string-append home "/.guile"))))
 
+  (define (set-user-module)
+    (set-current-module user-module)
+    (when (and (not (assoc-ref opts 'ignore-dot-guile?))
+               user-config
+               (file-exists? user-config))
+      (load user-config)))
+
+  (define script
+    (reverse
+     (filter-map (match-lambda
+                   (('script . script) script)
+                   (_ #f))
+                 opts)))
+
+  (define script-file
+    (let ((file (car script))
+          (directory (getcwd)))
+      (canonicalize-path
+       (cond ((string-prefix? "/" file) file)
+             (else (string-append directory "/" file))))))
+
   (with-error-handling
-    (let ((type (assoc-ref opts 'type)))
-      (call-with-connection (assoc-ref opts 'listen)
-        (lambda ()
-          (case type
-            ((guile)
-             (save-module-excursion
-              (lambda ()
-                (set-current-module user-module)
-                (when (and (not (assoc-ref opts 'ignore-dot-guile?))
-                           user-config
-                           (file-exists? user-config))
-                  (load user-config))
-
-                ;; Do not exit repl on SIGINT.
-                ((@@ (ice-9 top-repl) call-with-sigint)
-                 (lambda ()
-                   (start-repl))))))
-            ((machine)
-             (machine-repl))
-            (else
-             (leave (G_ "~a: unknown type of REPL~%") type))))))))
+
+    (unless (null? script)
+      ;; Run script
+      (save-module-excursion
+       (lambda ()
+         (set-program-arguments (cons script-file (cdr script)))
+         (set-user-module)
+         (load script-file))))
+
+    (when (null? script)
+      ;; Start REPL
+      (let ((type (assoc-ref opts 'type)))
+        (call-with-connection (assoc-ref opts 'listen)
+          (lambda ()
+            (case type
+              ((guile)
+               (save-module-excursion
+                (lambda ()
+                  (set-user-module)
+                  ;; Do not exit repl on SIGINT.
+                  ((@@ (ice-9 top-repl) call-with-sigint)
+                   (lambda ()
+                     (start-repl))))))
+              ((machine)
+               (machine-repl))
+              (else
+               (leave (G_ "~a: unknown type of REPL~%") type)))))))))
 
 ;; Local Variables:
 ;; eval: (put 'call-with-connection 'scheme-indent-function 1)
diff --git a/tests/guix-repl.sh b/tests/guix-repl.sh
new file mode 100644
index 0000000000..e1c2b8241f
--- /dev/null
+++ b/tests/guix-repl.sh
@@ -0,0 +1,84 @@
+# GNU Guix --- Functional package management for GNU
+# Copyright © 2020 Simon Tournier <zimon.toutoune <at> gmail.com>
+# Copyright © 2020 Konrad Hinsen <konrad.hinsen <at> fastmail.net>
+#
+# This file is part of GNU Guix.
+#
+# GNU Guix is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or (at
+# your option) any later version.
+#
+# GNU Guix is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+#
+# Test the `guix repl' command-line utility.
+#
+
+guix repl --version
+
+test_directory="`mktemp -d`"
+export test_directory
+trap 'chmod -Rf +w "$test_directory"; rm -rf "$test_directory"' EXIT
+
+tmpfile="$test_directory/foo.scm"
+rm -f "$tmpfile"
+trap 'rm -f "$tmpfile"' EXIT
+
+module_dir="t-guix-repl-$$"
+mkdir "$module_dir"
+trap 'rm -rf "$module_dir"' EXIT
+
+
+cat > "$tmpfile"<<EOF
+(use-modules (guix packages)
+             (gnu packages base))
+
+(format #t "~a\n" (package-name coreutils))
+EOF
+
+test "`guix repl "$tmpfile"`" = "coreutils"
+
+
+cat > "$module_dir/foo.scm"<<EOF
+(define-module (foo)
+  #:use-module (guix packages)
+  #:use-module (gnu packages base))
+
+(define-public dummy
+  (package (inherit hello)
+    (name "dummy")
+    (version "42")
+    (synopsis "dummy package")
+    (description "dummy package. Only used for testing purposes.")))
+EOF
+
+cat > "$tmpfile"<<EOF
+(use-modules (guix packages)
+             (foo))
+
+(format #t "~a\n" (package-version dummy))
+EOF
+
+test "`guix repl "$tmpfile" -L "$module_dir"`" = "42"
+
+cat > "$tmpfile"<<EOF
+(format #t "~a\n" (cdr (command-line)))
+EOF
+
+test "`guix repl -- "$tmpfile" -a b --input=foo.txt`" = "(-a b --input=foo.txt)"
+
+cat > "$tmpfile"<<EOF
+#!$(type -P env) -S guix repl --
+!#
+(format #t "~a\n" (cdr (command-line)))
+EOF
+chmod 755 $tmpfile
+
+test "`"$tmpfile" -a b --input=foo.txt`" = "(-a b --input=foo.txt)"
-- 
2.26.2





Information forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Sat, 13 Jun 2020 16:40:03 GMT) Full text and rfc822 format available.

Message #50 received at 41253 <at> debbugs.gnu.org (full text, mbox):

From: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
To: Ludovic Courtès <ludo <at> gnu.org>
Cc: 41253 <at> debbugs.gnu.org
Subject: Re: [bug#41253] [PATCH v4] guix repl: Add script execution.
Date: Sat, 13 Jun 2020 18:39:42 +0200
Hi Ludo,

Patch v5 is on its way! A few comments:

> Should be: [@var{file} @var{args}@dots{}]
> The square brackets show it’s optional.

OK.

>> +When a @var{file} argument is provided, @var{file} is
>> +executed as a Guile scripts:
>
> “When one or more @var{file} argument is provided, each @var{file} is
> executed as a Guile program:”

No, that's no longer true. Only one script can be run at a time, because

  guix repl script1.scm script2.scm

now means "run script1.scm with script2.scm as its argument". And therefore...

>   (define scripts  ;plural, no?

This is not a plural. But filter-map is indeed nicer!

>> +  (define script-file
>> +    (let ((file (car script))
>> +          (directory (getcwd)))
>> +      (canonicalize-path
>> +       (cond ((string-prefix? "/" file) file)
>> +             (else (string-append directory "/" file))))))
>
> I think we can just use file names as they arrive, without attempting to
> canonicalize them or anything.

That's what I thought (and tried) as well, at first. Problems:

 - It doesn't work when run via pre-inst-env with a non-absolute
   filename for the script. The script is looked up relative
   to the directory containing repl.scm.

 - The script filename is also the first item of (command-line)
   when called inside the script, and that's useful only it it's
   an absolute filename.

>> +cat > "$tmpfile"<<EOF
>> +#!/usr/bin/env -S guix repl --
>
> Rather:
>
>   #!$(type -P env)

I didn't know that was possible on a shebang line!

> Could you send an updated patch?

Done!

Cheers,
  Konrad




Information forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Sat, 13 Jun 2020 19:45:02 GMT) Full text and rfc822 format available.

Message #53 received at 41253 <at> debbugs.gnu.org (full text, mbox):

From: Ludovic Courtès <ludo <at> gnu.org>
To: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
Cc: 41253 <at> debbugs.gnu.org
Subject: Re: [bug#41253] [PATCH v4] guix repl: Add script execution.
Date: Sat, 13 Jun 2020 21:44:51 +0200
Hi,

Konrad Hinsen <konrad.hinsen <at> fastmail.net> skribis:

>> “When one or more @var{file} argument is provided, each @var{file} is
>> executed as a Guile program:”
>
> No, that's no longer true. Only one script can be run at a time, because
>
>   guix repl script1.scm script2.scm
>
> now means "run script1.scm with script2.scm as its argument". And therefore...

Ah OK, sorry for the confusion.

>>> +  (define script-file
>>> +    (let ((file (car script))
>>> +          (directory (getcwd)))
>>> +      (canonicalize-path
>>> +       (cond ((string-prefix? "/" file) file)
>>> +             (else (string-append directory "/" file))))))
>>
>> I think we can just use file names as they arrive, without attempting to
>> canonicalize them or anything.
>
> That's what I thought (and tried) as well, at first. Problems:
>
>  - It doesn't work when run via pre-inst-env with a non-absolute
>    filename for the script. The script is looked up relative
>    to the directory containing repl.scm.

Oh right, that’s because we’re using ‘load’.  We should instead do:

  (load-in-vicinity "." file)

Alternatively, (primitive-load file), but in that case the script would
be systematically interpreted.

>  - The script filename is also the first item of (command-line)
>    when called inside the script, and that's useful only it it's
>    an absolute filename.

In what way is it useful?

>>> +cat > "$tmpfile"<<EOF
>>> +#!/usr/bin/env -S guix repl --
>>
>> Rather:
>>
>>   #!$(type -P env)
>
> I didn't know that was possible on a shebang line!

It’s not, but here it’s evaluated as part of the here-document
expansion.

Thanks!

Ludo’.




Information forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Sun, 14 Jun 2020 07:01:02 GMT) Full text and rfc822 format available.

Message #56 received at 41253 <at> debbugs.gnu.org (full text, mbox):

From: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
To: 41253 <at> debbugs.gnu.org
Subject: [PATCH v6] guix repl: Add script execution.
Date: Sun, 14 Jun 2020 09:00:12 +0200
* guix/scripts/repl.scm: Add filename options for script execution.
* doc/guix.texi (Invoking guix repl): Document it.
* tests/guix-repl.sh: Test it.
* Makefile.am: (SH_TESTS): Add it.
---
 Makefile.am           |  1 +
 doc/guix.texi         | 51 +++++++++++++++++++++-----
 guix/scripts/repl.scm | 77 +++++++++++++++++++++++++--------------
 tests/guix-repl.sh    | 84 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 179 insertions(+), 34 deletions(-)
 create mode 100644 tests/guix-repl.sh

diff --git a/Makefile.am b/Makefile.am
index 9cf9318e8a..8988cdfa12 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -477,6 +477,7 @@ SH_TESTS =					\
   tests/guix-environment-container.sh		\
   tests/guix-graph.sh				\
   tests/guix-describe.sh			\
+  tests/guix-repl.sh     			\
   tests/guix-lint.sh
 
 TESTS = $(SCM_TESTS) $(SH_TESTS)
diff --git a/doc/guix.texi b/doc/guix.texi
index 15e077a41c..8ad3a833c6 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -239,7 +239,7 @@ Programming Interface
 * Derivations::                 Low-level interface to package derivations.
 * The Store Monad::             Purely functional interface to the store.
 * G-Expressions::               Manipulating build expressions.
-* Invoking guix repl::          Fiddling with Guix interactively.
+* Invoking guix repl::          Programming Guix in Guile
 
 Defining Packages
 
@@ -5474,7 +5474,7 @@ package definitions.
 * Derivations::                 Low-level interface to package derivations.
 * The Store Monad::             Purely functional interface to the store.
 * G-Expressions::               Manipulating build expressions.
-* Invoking guix repl::          Fiddling with Guix interactively.
+* Invoking guix repl::          Programming Guix in Guile
 @end menu
 
 @node Package Modules
@@ -8248,12 +8248,47 @@ has an associated gexp compiler, such as a @code{<package>}.
 @node Invoking guix repl
 @section Invoking @command{guix repl}
 
-@cindex REPL, read-eval-print loop
-The @command{guix repl} command spawns a Guile @dfn{read-eval-print loop}
-(REPL) for interactive programming (@pxref{Using Guile Interactively,,, guile,
-GNU Guile Reference Manual}).  Compared to just launching the @command{guile}
+@cindex REPL, read-eval-print loop, script
+The @command{guix repl} command makes it easier to program Guix in Guile
+by launching a Guile @dfn{read-eval-print loop} (REPL) for interactive
+programming (@pxref{Using Guile Interactively,,, guile,
+GNU Guile Reference Manual}), or by running Guile scripts
+(@pxref{Running Guile Scripts,,, guile,
+GNU Guile Reference Manual}).
+Compared to just launching the @command{guile}
 command, @command{guix repl} guarantees that all the Guix modules and all its
-dependencies are available in the search path.  You can use it this way:
+dependencies are available in the search path.
+
+The general syntax is:
+
+@example
+guix repl @var{options} [@var{file} @var{args}]
+@end example
+
+When a @var{file} argument is provided, @var{file} is
+executed as a Guile scripts:
+
+@example
+guix repl my-script.scm
+@end example
+
+To pass arguments to the script, use @code{--} to prevent them from
+being interpreted as arguments to @command{guix repl} itself:
+
+@example
+guix repl -- my-script.scm --input=foo.txt
+@end example
+
+To make a script executable directly from the shell, using the guix
+executable that is on the user's search path, add the following two
+lines at the top of the script:
+
+@example
+@code{#!/usr/bin/env -S guix repl --}
+@code{!#}
+@end example
+
+Without a file name argument, a Guile REPL is started:
 
 @example
 $ guix repl
@@ -8302,7 +8337,7 @@ Add @var{directory} to the front of the package module search path
 (@pxref{Package Modules}).
 
 This allows users to define their own packages and make them visible to
-the command-line tool.
+the script or REPL.
 
 @item -q
 Inhibit loading of the @file{~/.guile} file.  By default, that
diff --git a/guix/scripts/repl.scm b/guix/scripts/repl.scm
index ff1f208894..e2679f4301 100644
--- a/guix/scripts/repl.scm
+++ b/guix/scripts/repl.scm
@@ -1,6 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2018, 2019, 2020 Ludovic Courtès <ludo <at> gnu.org>
 ;;; Copyright © 2020 Simon Tournier <zimon.toutoune <at> gmail.com>
+;;; Copyright © 2020 Konrad Hinsen <konrad.hinsen <at> fastmail.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -22,6 +23,7 @@
   #:use-module (guix scripts)
   #:use-module (guix repl)
   #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-26)
   #:use-module (srfi srfi-37)
   #:use-module (ice-9 match)
   #:use-module (rnrs bytevectors)
@@ -32,7 +34,8 @@
 
 ;;; Commentary:
 ;;;
-;;; This command provides a Guile REPL
+;;; This command provides a Guile script runner and REPL in an environment
+;;; that contains all the modules comprising Guix.
 
 (define %default-options
   `((type . guile)))
@@ -63,8 +66,9 @@
 
 
 (define (show-help)
-  (display (G_ "Usage: guix repl [OPTIONS...]
-Start a Guile REPL in the Guix execution environment.\n"))
+  (display (G_ "Usage: guix repl [OPTIONS...] [-- FILE ARGS...]
+In the Guix execution environment, run FILE as a Guile script with
+command-line arguments ARGS.  If no FILE is given, start a Guile REPL.\n"))
   (display (G_ "
   -t, --type=TYPE        start a REPL of the given TYPE"))
   (display (G_ "
@@ -135,12 +139,13 @@ call THUNK."
 
 (define (guix-repl . args)
   (define opts
-    ;; Return the list of package names.
     (args-fold* args %options
                 (lambda (opt name arg result)
                   (leave (G_ "~A: unrecognized option~%") name))
                 (lambda (arg result)
-                  (leave (G_ "~A: extraneous argument~%") arg))
+                  (append `((script . ,arg)
+                            (ignore-dot-guile . #t))
+                          result))
                 %default-options))
 
   (define user-config
@@ -148,28 +153,48 @@ call THUNK."
            (lambda (home)
              (string-append home "/.guile"))))
 
+  (define (set-user-module)
+    (set-current-module user-module)
+    (when (and (not (assoc-ref opts 'ignore-dot-guile?))
+               user-config
+               (file-exists? user-config))
+      (load user-config)))
+
+  (define script
+    (reverse
+     (filter-map (match-lambda
+                   (('script . script) script)
+                   (_ #f))
+                 opts)))
+
   (with-error-handling
-    (let ((type (assoc-ref opts 'type)))
-      (call-with-connection (assoc-ref opts 'listen)
-        (lambda ()
-          (case type
-            ((guile)
-             (save-module-excursion
-              (lambda ()
-                (set-current-module user-module)
-                (when (and (not (assoc-ref opts 'ignore-dot-guile?))
-                           user-config
-                           (file-exists? user-config))
-                  (load user-config))
-
-                ;; Do not exit repl on SIGINT.
-                ((@@ (ice-9 top-repl) call-with-sigint)
-                 (lambda ()
-                   (start-repl))))))
-            ((machine)
-             (machine-repl))
-            (else
-             (leave (G_ "~a: unknown type of REPL~%") type))))))))
+
+    (unless (null? script)
+      ;; Run script
+      (save-module-excursion
+       (lambda ()
+         (set-program-arguments script)
+         (set-user-module)
+         (load-in-vicinity "." (car script)))))
+
+    (when (null? script)
+      ;; Start REPL
+      (let ((type (assoc-ref opts 'type)))
+        (call-with-connection (assoc-ref opts 'listen)
+          (lambda ()
+            (case type
+              ((guile)
+               (save-module-excursion
+                (lambda ()
+                  (set-user-module)
+                  ;; Do not exit repl on SIGINT.
+                  ((@@ (ice-9 top-repl) call-with-sigint)
+                   (lambda ()
+                     (start-repl))))))
+              ((machine)
+               (machine-repl))
+              (else
+               (leave (G_ "~a: unknown type of REPL~%") type)))))))))
 
 ;; Local Variables:
 ;; eval: (put 'call-with-connection 'scheme-indent-function 1)
diff --git a/tests/guix-repl.sh b/tests/guix-repl.sh
new file mode 100644
index 0000000000..e1c2b8241f
--- /dev/null
+++ b/tests/guix-repl.sh
@@ -0,0 +1,84 @@
+# GNU Guix --- Functional package management for GNU
+# Copyright © 2020 Simon Tournier <zimon.toutoune <at> gmail.com>
+# Copyright © 2020 Konrad Hinsen <konrad.hinsen <at> fastmail.net>
+#
+# This file is part of GNU Guix.
+#
+# GNU Guix is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or (at
+# your option) any later version.
+#
+# GNU Guix is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+#
+# Test the `guix repl' command-line utility.
+#
+
+guix repl --version
+
+test_directory="`mktemp -d`"
+export test_directory
+trap 'chmod -Rf +w "$test_directory"; rm -rf "$test_directory"' EXIT
+
+tmpfile="$test_directory/foo.scm"
+rm -f "$tmpfile"
+trap 'rm -f "$tmpfile"' EXIT
+
+module_dir="t-guix-repl-$$"
+mkdir "$module_dir"
+trap 'rm -rf "$module_dir"' EXIT
+
+
+cat > "$tmpfile"<<EOF
+(use-modules (guix packages)
+             (gnu packages base))
+
+(format #t "~a\n" (package-name coreutils))
+EOF
+
+test "`guix repl "$tmpfile"`" = "coreutils"
+
+
+cat > "$module_dir/foo.scm"<<EOF
+(define-module (foo)
+  #:use-module (guix packages)
+  #:use-module (gnu packages base))
+
+(define-public dummy
+  (package (inherit hello)
+    (name "dummy")
+    (version "42")
+    (synopsis "dummy package")
+    (description "dummy package. Only used for testing purposes.")))
+EOF
+
+cat > "$tmpfile"<<EOF
+(use-modules (guix packages)
+             (foo))
+
+(format #t "~a\n" (package-version dummy))
+EOF
+
+test "`guix repl "$tmpfile" -L "$module_dir"`" = "42"
+
+cat > "$tmpfile"<<EOF
+(format #t "~a\n" (cdr (command-line)))
+EOF
+
+test "`guix repl -- "$tmpfile" -a b --input=foo.txt`" = "(-a b --input=foo.txt)"
+
+cat > "$tmpfile"<<EOF
+#!$(type -P env) -S guix repl --
+!#
+(format #t "~a\n" (cdr (command-line)))
+EOF
+chmod 755 $tmpfile
+
+test "`"$tmpfile" -a b --input=foo.txt`" = "(-a b --input=foo.txt)"
-- 
2.26.2





Information forwarded to guix-patches <at> gnu.org:
bug#41253; Package guix-patches. (Sun, 14 Jun 2020 07:03:01 GMT) Full text and rfc822 format available.

Message #59 received at 41253 <at> debbugs.gnu.org (full text, mbox):

From: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
To: Ludovic Courtès <ludo <at> gnu.org>
Cc: 41253 <at> debbugs.gnu.org
Subject: Re: [bug#41253] [PATCH v4] guix repl: Add script execution.
Date: Sun, 14 Jun 2020 09:02:48 +0200
Hi Ludo,

> Oh right, that’s because we’re using ‘load’.  We should instead do:
>
>   (load-in-vicinity "." file)

Nice! That makes it cleaner indeed, since...

>>  - The script filename is also the first item of (command-line)
>>    when called inside the script, and that's useful only it it's
>>    an absolute filename.
>
> In what way is it useful?

I though it was a POSIX requirement, but (1) I didn't find anything on
that topic and (2) plaing Guile just passes on what I type on the
command line, so I won't try to do "better".

v6 is on the way!

Cheers,
  Konrad




Reply sent to Ludovic Courtès <ludo <at> gnu.org>:
You have taken responsibility. (Sun, 14 Jun 2020 20:51:01 GMT) Full text and rfc822 format available.

Notification sent to Konrad Hinsen <konrad.hinsen <at> fastmail.net>:
bug acknowledged by developer. (Sun, 14 Jun 2020 20:51:01 GMT) Full text and rfc822 format available.

Message #64 received at 41253-done <at> debbugs.gnu.org (full text, mbox):

From: Ludovic Courtès <ludo <at> gnu.org>
To: Konrad Hinsen <konrad.hinsen <at> fastmail.net>
Cc: 41253-done <at> debbugs.gnu.org
Subject: Re: [bug#41253] [PATCH v6] guix repl: Add script execution.
Date: Sun, 14 Jun 2020 22:50:03 +0200
Hi,

Konrad Hinsen <konrad.hinsen <at> fastmail.net> skribis:

> * guix/scripts/repl.scm: Add filename options for script execution.
> * doc/guix.texi (Invoking guix repl): Document it.
> * tests/guix-repl.sh: Test it.
> * Makefile.am: (SH_TESTS): Add it.

Perfect, applied!

If you want you can followup with an update of ‘etc/news.scm’ to that
people can learn about this change.

Thank you for your work & for your patience!

Ludo’.




bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Mon, 13 Jul 2020 11:24:06 GMT) Full text and rfc822 format available.

This bug report was last modified 3 years and 288 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.