aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonrad Hinsen <konrad.hinsen@fastmail.net>2020-06-14 09:00:12 +0200
committerLudovic Courtès <ludo@gnu.org>2020-06-14 23:02:36 +0200
commitc924e541390f9595d819edc33c19d979917c15ec (patch)
tree37d4854ff1f2b4b20c4826af1e6b76161b21a123
parent1b917f99b5fb2968a381ef0acd43db7f711f2db9 (diff)
downloadguix-c924e541390f9595d819edc33c19d979917c15ec.tar
guix-c924e541390f9595d819edc33c19d979917c15ec.tar.gz
guix repl: Add script execution.
* 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. Signed-off-by: Ludovic Courtès <ludo@gnu.org>
-rw-r--r--Makefile.am1
-rw-r--r--doc/guix.texi51
-rw-r--r--guix/scripts/repl.scm77
-rw-r--r--tests/guix-repl.sh84
4 files changed, 179 insertions, 34 deletions
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 510347b222..d55eaff02c 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."
(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)"