@@ -255,6 +255,7 @@ MODULES = \
guix/scripts/authenticate.scm \
guix/scripts/refresh.scm \
guix/scripts/repl.scm \
+ guix/scripts/run.scm \
guix/scripts/describe.scm \
guix/scripts/system.scm \
guix/scripts/system/search.scm \
@@ -234,7 +234,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 run:: Programming Guix in Guile
Defining Packages
@@ -1154,7 +1154,7 @@ The @command{guix} command must be in the search path on the build
machines. You can check whether this is the case by running:
@example
-ssh build-machine guix repl --version
+ssh build-machine guix run --version
@end example
There is one last thing to do once @file{machines.scm} is in place. As
@@ -4259,7 +4259,7 @@ revisions in arbitrary ways.
@cindex inferior packages
Technically, an ``inferior'' is essentially a separate Guix process connected
-to your main Guix process through a REPL (@pxref{Invoking guix repl}). The
+to your main Guix process through a REPL (@pxref{Invoking guix run}). The
@code{(guix inferior)} module allows you to create inferiors and to
communicate with them. It also provides a high-level interface to browse and
manipulate the packages that an inferior provides---@dfn{inferior packages}.
@@ -4318,7 +4318,7 @@ As a side effect, this procedure may build or substitute binaries for
@deffn {Scheme Procedure} open-inferior @var{directory} @
[#:command "bin/guix"]
Open the inferior Guix in @var{directory}, running
-@code{@var{directory}/@var{command} repl} or equivalent. Return @code{#f} if
+@code{@var{directory}/@var{command} run} or equivalent. Return @code{#f} if
the inferior could not be launched.
@end deffn
@@ -5346,7 +5346,8 @@ 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 run:: Programming Guix in Guile
+
@end menu
@node Package Modules
@@ -8057,25 +8058,43 @@ corresponding to @var{obj} for @var{system}, cross-compiling for
has an associated gexp compiler, such as a @code{<package>}.
@end deffn
-@node Invoking guix repl
-@section Invoking @command{guix repl}
+@node Invoking guix run
+@section Invoking @command{guix run}
+
+@cindex script, REPL, read-eval-print loop
+The @command{guix run} command makes it easier to program Guix in Guile,
+either by running Guile scripts (@pxref{Running Guile Scripts,,, guile,
+GNU Guile Reference Manual}) or by launching 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}
+command, @command{guix run} guarantees that all the Guix modules and all its
+dependencies are available in the search path.
+
+The general syntax is:
+
+@example
+guix run @var{options} @var{file}
+@end example
+
+When a @var{file} argument is provided, @var{file} is executed as a Guile
+script:
+
+@example
+$ guix run my-script.scm
+@end example
-@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}
-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:
+Otherwise a Guile REPL is started:
@example
-$ guix repl
+$ guix run
scheme@@(guile-user)> ,use (gnu packages base)
scheme@@(guile-user)> coreutils
$1 = #<package coreutils@@8.29 gnu/packages/base.scm:327 3e28300>
@end example
@cindex inferiors
-In addition, @command{guix repl} implements a simple machine-readable REPL
+In addition, @command{guix run} implements a simple machine-readable REPL
protocol for use by @code{(guix inferior)}, a facility to interact with
@dfn{inferiors}, separate processes running a potentially different revision
of Guix.
@@ -8114,7 +8133,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 command-line tool.
@item -q
Inhibit loading of the @file{~/.guile} file. By default, that
@@ -1,6 +1,5 @@
;;; 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.
;;;
@@ -18,159 +17,11 @@
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (guix scripts repl)
- #:use-module (guix ui)
- #:use-module (guix scripts)
- #:use-module (guix repl)
- #:use-module (srfi srfi-1)
- #:use-module (srfi srfi-37)
- #:use-module (ice-9 match)
- #:use-module (rnrs bytevectors)
- #:autoload (system repl repl) (start-repl)
- #:autoload (system repl server)
- (make-tcp-server-socket make-unix-domain-server-socket)
+ #:use-module (guix scripts run)
#:export (guix-repl))
;;; Commentary:
;;;
-;;; This command provides a Guile REPL
+;;; This is an alias for "guix run", for backwards compatibility
-(define %default-options
- `((type . guile)))
-
-(define %options
- (list (option '(#\h "help") #f #f
- (lambda args
- (show-help)
- (exit 0)))
- (option '(#\V "version") #f #f
- (lambda args
- (show-version-and-exit "guix repl")))
- (option '(#\t "type") #t #f
- (lambda (opt name arg result)
- (alist-cons 'type (string->symbol arg) result)))
- (option '("listen") #t #f
- (lambda (opt name arg result)
- (alist-cons 'listen arg result)))
- (option '(#\q) #f #f
- (lambda (opt name arg result)
- (alist-cons 'ignore-dot-guile? #t result)))
- (option '(#\L "load-path") #t #f
- (lambda (opt name arg result)
- ;; XXX: Imperatively modify the search paths.
- (set! %load-path (cons arg %load-path))
- (set! %load-compiled-path (cons arg %load-compiled-path))
- result))))
-
-
-(define (show-help)
- (display (G_ "Usage: guix repl [OPTIONS...]
-Start a Guile REPL in the Guix execution environment.\n"))
- (display (G_ "
- -t, --type=TYPE start a REPL of the given TYPE"))
- (display (G_ "
- --listen=ENDPOINT listen to ENDPOINT instead of standard input"))
- (display (G_ "
- -q inhibit loading of ~/.guile"))
- (newline)
- (display (G_ "
- -L, --load-path=DIR prepend DIR to the package module search path"))
- (newline)
- (display (G_ "
- -h, --help display this help and exit"))
- (display (G_ "
- -V, --version display version information and exit"))
- (newline)
- (show-bug-report-information))
-
-(define user-module
- ;; Module where we execute user code.
- (let ((module (resolve-module '(guix-user) #f #f #:ensure #t)))
- (beautify-user-module! module)
- module))
-
-(define (call-with-connection spec thunk)
- "Dynamically-bind the current input and output ports according to SPEC and
-call THUNK."
- (if (not spec)
- (thunk)
-
- ;; Note: the "PROTO:" prefix in SPEC is here so that we can eventually
- ;; parse things like "fd:123" in a non-ambiguous way.
- (match (string-index spec #\:)
- (#f
- (leave (G_ "~A: invalid listen specification~%") spec))
- (index
- (let ((protocol (string-take spec index))
- (address (string-drop spec (+ index 1))))
- (define socket
- (match protocol
- ("tcp"
- (make-tcp-server-socket #:port (string->number address)))
- ("unix"
- (make-unix-domain-server-socket #:path address))
- (_
- (leave (G_ "~A: unsupported protocol family~%")
- protocol))))
-
- (listen socket 10)
- (let loop ()
- (match (accept socket)
- ((connection . address)
- (if (= AF_UNIX (sockaddr:fam address))
- (info (G_ "accepted connection~%"))
- (info (G_ "accepted connection from ~a~%")
- (inet-ntop (sockaddr:fam address)
- (sockaddr:addr address))))
- (dynamic-wind
- (const #t)
- (lambda ()
- (parameterize ((current-input-port connection)
- (current-output-port connection))
- (thunk)))
- (lambda ()
- (false-if-exception (close-port connection))
- (info (G_ "connection closed~%"))))))
- (loop)))))))
-
-
-(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))
- %default-options))
-
- (define user-config
- (and=> (getenv "HOME")
- (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))
-
- ;; 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:
+(define guix-repl guix-run)
new file mode 100644
@@ -0,0 +1,189 @@
+;;; 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.
+;;;
+;;; 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/>.
+
+(define-module (guix scripts run)
+ #:use-module (guix ui)
+ #:use-module (guix scripts)
+ #:use-module (guix repl)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-37)
+ #:use-module (ice-9 match)
+ #:use-module (rnrs bytevectors)
+ #:autoload (system repl repl) (start-repl)
+ #:autoload (system repl server)
+ (make-tcp-server-socket make-unix-domain-server-socket)
+ #:export (guix-run))
+
+;;; Commentary:
+;;;
+;;; This command provides a Guile script runner and REPL in an environment
+;;; that contains all the modules comprising Guix.
+
+(define %default-options
+ `((type . guile)))
+
+(define %options
+ (list (option '(#\h "help") #f #f
+ (lambda args
+ (show-help)
+ (exit 0)))
+ (option '(#\V "version") #f #f
+ (lambda args
+ (show-version-and-exit "guix repl")))
+ (option '(#\t "type") #t #f
+ (lambda (opt name arg result)
+ (alist-cons 'type (string->symbol arg) result)))
+ (option '("listen") #t #f
+ (lambda (opt name arg result)
+ (alist-cons 'listen arg result)))
+ (option '(#\q) #f #f
+ (lambda (opt name arg result)
+ (alist-cons 'ignore-dot-guile? #t result)))
+ (option '(#\L "load-path") #t #f
+ (lambda (opt name arg result)
+ ;; XXX: Imperatively modify the search paths.
+ (set! %load-path (cons arg %load-path))
+ (set! %load-compiled-path (cons arg %load-compiled-path))
+ result))))
+
+
+(define (show-help)
+ (display (G_ "Usage: guix run [OPTIONS...] [FILE]
+Run FILE as a Guile script, or start a Guile REPL, in the Guix
+execution environment.\n"))
+ (display (G_ "
+ -t, --type=TYPE start a REPL of the given TYPE"))
+ (display (G_ "
+ --listen=ENDPOINT listen to ENDPOINT instead of standard input"))
+ (display (G_ "
+ -q inhibit loading of ~/.guile"))
+ (newline)
+ (display (G_ "
+ -L, --load-path=DIR prepend DIR to the package module search path"))
+ (newline)
+ (display (G_ "
+ -h, --help display this help and exit"))
+ (display (G_ "
+ -V, --version display version information and exit"))
+ (newline)
+ (show-bug-report-information))
+
+(define user-module
+ ;; Module where we execute user code.
+ (let ((module (resolve-module '(guix-user) #f #f #:ensure #t)))
+ (beautify-user-module! module)
+ module))
+
+(define (call-with-connection spec thunk)
+ "Dynamically-bind the current input and output ports according to SPEC and
+call THUNK."
+ (if (not spec)
+ (thunk)
+
+ ;; Note: the "PROTO:" prefix in SPEC is here so that we can eventually
+ ;; parse things like "fd:123" in a non-ambiguous way.
+ (match (string-index spec #\:)
+ (#f
+ (leave (G_ "~A: invalid listen specification~%") spec))
+ (index
+ (let ((protocol (string-take spec index))
+ (address (string-drop spec (+ index 1))))
+ (define socket
+ (match protocol
+ ("tcp"
+ (make-tcp-server-socket #:port (string->number address)))
+ ("unix"
+ (make-unix-domain-server-socket #:path address))
+ (_
+ (leave (G_ "~A: unsupported protocol family~%")
+ protocol))))
+
+ (listen socket 10)
+ (let loop ()
+ (match (accept socket)
+ ((connection . address)
+ (if (= AF_UNIX (sockaddr:fam address))
+ (info (G_ "accepted connection~%"))
+ (info (G_ "accepted connection from ~a~%")
+ (inet-ntop (sockaddr:fam address)
+ (sockaddr:addr address))))
+ (dynamic-wind
+ (const #t)
+ (lambda ()
+ (parameterize ((current-input-port connection)
+ (current-output-port connection))
+ (thunk)))
+ (lambda ()
+ (false-if-exception (close-port connection))
+ (info (G_ "connection closed~%"))))))
+ (loop)))))))
+
+
+(define (guix-run . args)
+ (define opts
+ (args-fold* args %options
+ (lambda (opt name arg result)
+ (leave (G_ "~A: unrecognized option~%") name))
+ (lambda (arg result)
+ (when (assq 'argument result)
+ (leave (G_ "~A: extraneous argument~%") arg))
+ (alist-cons 'argument arg 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 ((script (assoc-ref opts 'argument))
+ (type (assoc-ref opts 'type)))
+ (if script
+ (save-module-excursion
+ (lambda ()
+ (set-user-module)
+ (load script)))
+ (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:
+ )