ui: Allow evaluating multi-expressions strings with read/eval.

This can be useful when evaluating a scheme-file store output for example,
which has multiple top level expressions.

* guix/ui.scm (read/eval): Also accept a port object as argument.  Read and
evaluate all expressions from input port or string.

Change-Id: I0213706fa4824c3a8ffe5d93f44f263048cb62c2
This commit is contained in:
Maxim Cournoyer 2025-05-05 13:30:29 +09:00
parent bc2e923c19
commit 18ed22536d
No known key found for this signature in database
GPG key ID: 1260E46482E63562
2 changed files with 43 additions and 9 deletions

View file

@ -15,7 +15,7 @@
;;; Copyright © 2019, 2020 Tobias Geerinckx-Rice <me@tobias.gr>
;;; Copyright © 2019, 2021 Simon Tournier <zimon.toutoune@gmail.com>
;;; Copyright © 2020 Arun Isaac <arunisaac@systemreboot.net>
;;; Copyright © 2020 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; Copyright © 2020, 2025 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; Copyright © 2018 Steve Sprang <scs@stevesprang.com>
;;; Copyright © 2022 Taiju HIGASHI <higashi@taiju.info>
;;; Copyright © 2022 Liliana Marie Prikler <liliana.prikler@gmail.com>
@ -926,13 +926,18 @@ similar."
module)))
(define (read/eval str)
"Read and evaluate STR, raising an error if something goes wrong."
(let ((exp (catch #t
(lambda ()
(call-with-input-string str read))
(lambda args
(leave (G_ "failed to read expression ~s: ~s~%")
str args)))))
"Read and evaluate STR, which can also be a port, raising an error if
something goes wrong. STR may contain one or more expressions; the return
value is that of the last evaluated expression."
(define (read/safe port)
(catch #t
(lambda ()
(read port))
(lambda args
(leave (G_ "failed to read expression ~s: ~s~%")
str args))))
(define (eval/safe exp)
(catch #t
(lambda ()
(eval exp (force %guix-user-module)))
@ -956,7 +961,19 @@ similar."
((error args ...)
(apply display-error #f (current-error-port) args))
(what? #f))
(exit 1)))))
(exit 1))))
(let ((call-with-port-or-string (if (port? str)
call-with-port
call-with-input-string)))
(call-with-port-or-string
str
(lambda (port)
(let loop ((exp (read/safe port))
(result #f))
(if (eof-object? exp)
result
(loop (read/safe port) (eval/safe exp))))))))
(define (read/eval-package-expression str)
"Read and evaluate STR and return the package it refers to, or exit an