* [bug#41253] [PATCH] guix: add script execution to "guix repl"
@ 2020-05-14 9:18 Konrad Hinsen
2020-05-14 16:25 ` [bug#41253] [PATCH v2] guix repl: Add script execution zimoun
2020-05-14 16:31 ` [bug#41253] [PATCH] guix: add script execution to "guix repl" zimoun
0 siblings, 2 replies; 20+ messages in thread
From: Konrad Hinsen @ 2020-05-14 9:18 UTC (permalink / raw)
To: 41253
* 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@gnu.org>
;;; Copyright © 2020 Simon Tournier <zimon.toutoune@gmail.com>
+;;; Copyright © 2020 Konrad Hinsen <konrad.hinsen@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."
\f
(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
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [bug#41253] [PATCH v2] guix repl: Add script execution.
2020-05-14 9:18 [bug#41253] [PATCH] guix: add script execution to "guix repl" Konrad Hinsen
@ 2020-05-14 16:25 ` zimoun
2020-05-29 10:11 ` [bug#41253] [PATCH v3] " Konrad Hinsen
2020-05-14 16:31 ` [bug#41253] [PATCH] guix: add script execution to "guix repl" zimoun
1 sibling, 1 reply; 20+ messages in thread
From: zimoun @ 2020-05-14 16:25 UTC (permalink / raw)
To: 41253; +Cc: Konrad Hinsen
From: Konrad Hinsen <konrad.hinsen@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@gnu.org>
;;; Copyright © 2020 Simon Tournier <zimon.toutoune@gmail.com>
+;;; Copyright © 2020 Konrad Hinsen <konrad.hinsen@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."
\f
(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@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
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [bug#41253] [PATCH] guix: add script execution to "guix repl"
2020-05-14 9:18 [bug#41253] [PATCH] guix: add script execution to "guix repl" Konrad Hinsen
2020-05-14 16:25 ` [bug#41253] [PATCH v2] guix repl: Add script execution zimoun
@ 2020-05-14 16:31 ` zimoun
2020-05-29 10:16 ` Konrad Hinsen
1 sibling, 1 reply; 20+ messages in thread
From: zimoun @ 2020-05-14 16:31 UTC (permalink / raw)
To: Konrad Hinsen; +Cc: 41253
Dear Konrad,
Nice!
Thank you!
On Thu, 14 May 2020 at 11:19, Konrad Hinsen <konrad.hinsen@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
^ permalink raw reply [flat|nested] 20+ messages in thread
* [bug#41253] [PATCH v3] guix repl: Add script execution.
2020-05-14 16:25 ` [bug#41253] [PATCH v2] guix repl: Add script execution zimoun
@ 2020-05-29 10:11 ` Konrad Hinsen
2020-06-04 15:06 ` Ludovic Courtès
2020-06-06 5:18 ` [bug#41253] [PATCH v4] " Konrad Hinsen
0 siblings, 2 replies; 20+ messages in thread
From: Konrad Hinsen @ 2020-05-29 10:11 UTC (permalink / raw)
To: 41253, zimoun
* 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@gnu.org>
;;; Copyright © 2020 Simon Tournier <zimon.toutoune@gmail.com>
+;;; Copyright © 2020 Konrad Hinsen <konrad.hinsen@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."
\f
(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@gmail.com>
+# Copyright © 2020 Konrad Hinsen <konrad.hinsen@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
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [bug#41253] [PATCH] guix: add script execution to "guix repl"
2020-05-14 16:31 ` [bug#41253] [PATCH] guix: add script execution to "guix repl" zimoun
@ 2020-05-29 10:16 ` Konrad Hinsen
2020-05-29 13:53 ` zimoun
0 siblings, 1 reply; 20+ messages in thread
From: Konrad Hinsen @ 2020-05-29 10:16 UTC (permalink / raw)
To: zimoun; +Cc: 41253
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@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
^ permalink raw reply [flat|nested] 20+ messages in thread
* [bug#41253] [PATCH] guix: add script execution to "guix repl"
2020-05-29 10:16 ` Konrad Hinsen
@ 2020-05-29 13:53 ` zimoun
2020-05-29 17:21 ` Konrad Hinsen
0 siblings, 1 reply; 20+ messages in thread
From: zimoun @ 2020-05-29 13:53 UTC (permalink / raw)
To: Konrad Hinsen; +Cc: 41253
Hi Konrad,
On Fri, 29 May 2020 at 12:16, Konrad Hinsen <konrad.hinsen@fastmail.net> wrote:
> I just submitted a v3, following a thread on help-guix
> (see https://www.mail-archive.com/help-guix@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?
^ permalink raw reply [flat|nested] 20+ messages in thread
* [bug#41253] [PATCH] guix: add script execution to "guix repl"
2020-05-29 13:53 ` zimoun
@ 2020-05-29 17:21 ` Konrad Hinsen
0 siblings, 0 replies; 20+ messages in thread
From: Konrad Hinsen @ 2020-05-29 17:21 UTC (permalink / raw)
To: zimoun; +Cc: 41253
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
^ permalink raw reply [flat|nested] 20+ messages in thread
* [bug#41253] [PATCH v3] guix repl: Add script execution.
2020-05-29 10:11 ` [bug#41253] [PATCH v3] " Konrad Hinsen
@ 2020-06-04 15:06 ` Ludovic Courtès
2020-06-05 8:48 ` Konrad Hinsen
2020-06-06 5:18 ` [bug#41253] [PATCH v4] " Konrad Hinsen
1 sibling, 1 reply; 20+ messages in thread
From: Ludovic Courtès @ 2020-06-04 15:06 UTC (permalink / raw)
To: Konrad Hinsen; +Cc: 41253, zimoun
Hello!
Konrad Hinsen <konrad.hinsen@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’.
^ permalink raw reply [flat|nested] 20+ messages in thread
* [bug#41253] [PATCH v3] guix repl: Add script execution.
2020-06-04 15:06 ` Ludovic Courtès
@ 2020-06-05 8:48 ` Konrad Hinsen
2020-06-05 10:18 ` Konrad Hinsen
2020-06-05 16:36 ` Ludovic Courtès
0 siblings, 2 replies; 20+ messages in thread
From: Konrad Hinsen @ 2020-06-05 8:48 UTC (permalink / raw)
To: Ludovic Courtès; +Cc: 41253, zimoun
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@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@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
^ permalink raw reply [flat|nested] 20+ messages in thread
* [bug#41253] [PATCH v3] guix repl: Add script execution.
2020-06-05 8:48 ` Konrad Hinsen
@ 2020-06-05 10:18 ` Konrad Hinsen
2020-06-05 16:36 ` Ludovic Courtès
1 sibling, 0 replies; 20+ messages in thread
From: Konrad Hinsen @ 2020-06-05 10:18 UTC (permalink / raw)
To: Ludovic Courtès; +Cc: 41253, zimoun
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@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
^ permalink raw reply [flat|nested] 20+ messages in thread
* [bug#41253] [PATCH v3] guix repl: Add script execution.
2020-06-05 8:48 ` Konrad Hinsen
2020-06-05 10:18 ` Konrad Hinsen
@ 2020-06-05 16:36 ` Ludovic Courtès
2020-06-06 5:22 ` Konrad Hinsen
1 sibling, 1 reply; 20+ messages in thread
From: Ludovic Courtès @ 2020-06-05 16:36 UTC (permalink / raw)
To: Konrad Hinsen; +Cc: 41253, zimoun
Hello Konrad,
Konrad Hinsen <konrad.hinsen@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@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@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@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’.
^ permalink raw reply [flat|nested] 20+ messages in thread
* [bug#41253] [PATCH v4] guix repl: Add script execution.
2020-05-29 10:11 ` [bug#41253] [PATCH v3] " Konrad Hinsen
2020-06-04 15:06 ` Ludovic Courtès
@ 2020-06-06 5:18 ` Konrad Hinsen
2020-06-12 15:58 ` Ludovic Courtès
2020-06-13 16:34 ` [bug#41253] [PATCH v5] " Konrad Hinsen
1 sibling, 2 replies; 20+ messages in thread
From: Konrad Hinsen @ 2020-06-06 5:18 UTC (permalink / raw)
To: 41253
* 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@gnu.org>
;;; Copyright © 2020 Simon Tournier <zimon.toutoune@gmail.com>
+;;; Copyright © 2020 Konrad Hinsen <konrad.hinsen@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."
\f
(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@gmail.com>
+# Copyright © 2020 Konrad Hinsen <konrad.hinsen@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
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [bug#41253] [PATCH v3] guix repl: Add script execution.
2020-06-05 16:36 ` Ludovic Courtès
@ 2020-06-06 5:22 ` Konrad Hinsen
0 siblings, 0 replies; 20+ messages in thread
From: Konrad Hinsen @ 2020-06-06 5:22 UTC (permalink / raw)
To: Ludovic Courtès; +Cc: 41253, zimoun
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.
^ permalink raw reply [flat|nested] 20+ messages in thread
* [bug#41253] [PATCH v4] guix repl: Add script execution.
2020-06-06 5:18 ` [bug#41253] [PATCH v4] " Konrad Hinsen
@ 2020-06-12 15:58 ` Ludovic Courtès
2020-06-13 16:39 ` Konrad Hinsen
2020-06-13 16:34 ` [bug#41253] [PATCH v5] " Konrad Hinsen
1 sibling, 1 reply; 20+ messages in thread
From: Ludovic Courtès @ 2020-06-12 15:58 UTC (permalink / raw)
To: Konrad Hinsen; +Cc: 41253
Hi, and sorry for the delay!
Konrad Hinsen <konrad.hinsen@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’.
^ permalink raw reply [flat|nested] 20+ messages in thread
* [bug#41253] [PATCH v5] guix repl: Add script execution.
2020-06-06 5:18 ` [bug#41253] [PATCH v4] " Konrad Hinsen
2020-06-12 15:58 ` Ludovic Courtès
@ 2020-06-13 16:34 ` Konrad Hinsen
2020-06-14 7:00 ` [bug#41253] [PATCH v6] " Konrad Hinsen
1 sibling, 1 reply; 20+ messages in thread
From: Konrad Hinsen @ 2020-06-13 16:34 UTC (permalink / raw)
To: 41253
* 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@gnu.org>
;;; Copyright © 2020 Simon Tournier <zimon.toutoune@gmail.com>
+;;; Copyright © 2020 Konrad Hinsen <konrad.hinsen@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."
\f
(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@gmail.com>
+# Copyright © 2020 Konrad Hinsen <konrad.hinsen@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
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [bug#41253] [PATCH v4] guix repl: Add script execution.
2020-06-12 15:58 ` Ludovic Courtès
@ 2020-06-13 16:39 ` Konrad Hinsen
2020-06-13 19:44 ` Ludovic Courtès
0 siblings, 1 reply; 20+ messages in thread
From: Konrad Hinsen @ 2020-06-13 16:39 UTC (permalink / raw)
To: Ludovic Courtès; +Cc: 41253
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
^ permalink raw reply [flat|nested] 20+ messages in thread
* [bug#41253] [PATCH v4] guix repl: Add script execution.
2020-06-13 16:39 ` Konrad Hinsen
@ 2020-06-13 19:44 ` Ludovic Courtès
2020-06-14 7:02 ` Konrad Hinsen
0 siblings, 1 reply; 20+ messages in thread
From: Ludovic Courtès @ 2020-06-13 19:44 UTC (permalink / raw)
To: Konrad Hinsen; +Cc: 41253
Hi,
Konrad Hinsen <konrad.hinsen@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’.
^ permalink raw reply [flat|nested] 20+ messages in thread
* [bug#41253] [PATCH v6] guix repl: Add script execution.
2020-06-13 16:34 ` [bug#41253] [PATCH v5] " Konrad Hinsen
@ 2020-06-14 7:00 ` Konrad Hinsen
2020-06-14 20:50 ` bug#41253: " Ludovic Courtès
0 siblings, 1 reply; 20+ messages in thread
From: Konrad Hinsen @ 2020-06-14 7:00 UTC (permalink / raw)
To: 41253
* 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@gnu.org>
;;; Copyright © 2020 Simon Tournier <zimon.toutoune@gmail.com>
+;;; Copyright © 2020 Konrad Hinsen <konrad.hinsen@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."
\f
(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@gmail.com>
+# Copyright © 2020 Konrad Hinsen <konrad.hinsen@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
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [bug#41253] [PATCH v4] guix repl: Add script execution.
2020-06-13 19:44 ` Ludovic Courtès
@ 2020-06-14 7:02 ` Konrad Hinsen
0 siblings, 0 replies; 20+ messages in thread
From: Konrad Hinsen @ 2020-06-14 7:02 UTC (permalink / raw)
To: Ludovic Courtès; +Cc: 41253
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
^ permalink raw reply [flat|nested] 20+ messages in thread
* bug#41253: [PATCH v6] guix repl: Add script execution.
2020-06-14 7:00 ` [bug#41253] [PATCH v6] " Konrad Hinsen
@ 2020-06-14 20:50 ` Ludovic Courtès
0 siblings, 0 replies; 20+ messages in thread
From: Ludovic Courtès @ 2020-06-14 20:50 UTC (permalink / raw)
To: Konrad Hinsen; +Cc: 41253-done
Hi,
Konrad Hinsen <konrad.hinsen@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’.
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2020-06-14 20:51 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-05-14 9:18 [bug#41253] [PATCH] guix: add script execution to "guix repl" Konrad Hinsen
2020-05-14 16:25 ` [bug#41253] [PATCH v2] guix repl: Add script execution zimoun
2020-05-29 10:11 ` [bug#41253] [PATCH v3] " Konrad Hinsen
2020-06-04 15:06 ` Ludovic Courtès
2020-06-05 8:48 ` Konrad Hinsen
2020-06-05 10:18 ` Konrad Hinsen
2020-06-05 16:36 ` Ludovic Courtès
2020-06-06 5:22 ` Konrad Hinsen
2020-06-06 5:18 ` [bug#41253] [PATCH v4] " Konrad Hinsen
2020-06-12 15:58 ` Ludovic Courtès
2020-06-13 16:39 ` Konrad Hinsen
2020-06-13 19:44 ` Ludovic Courtès
2020-06-14 7:02 ` Konrad Hinsen
2020-06-13 16:34 ` [bug#41253] [PATCH v5] " Konrad Hinsen
2020-06-14 7:00 ` [bug#41253] [PATCH v6] " Konrad Hinsen
2020-06-14 20:50 ` bug#41253: " Ludovic Courtès
2020-05-14 16:31 ` [bug#41253] [PATCH] guix: add script execution to "guix repl" zimoun
2020-05-29 10:16 ` Konrad Hinsen
2020-05-29 13:53 ` zimoun
2020-05-29 17:21 ` Konrad Hinsen
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/guix.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.