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>
This commit is contained in:
Konrad Hinsen 2020-06-14 09:00:12 +02:00 committed by Ludovic Courtès
parent 1b917f99b5
commit c924e54139
No known key found for this signature in database
GPG Key ID: 090B11993D9AEBB5
4 changed files with 179 additions and 34 deletions

View File

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

View File

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

View File

@ -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"))))
(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))
(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)))
;; 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))))))))
(define script
(reverse
(filter-map (match-lambda
(('script . script) script)
(_ #f))
opts)))
(with-error-handling
(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)

84
tests/guix-repl.sh Normal file
View File

@ -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)"