diff options
| -rw-r--r-- | doc/guix.texi | 19 | ||||
| -rw-r--r-- | guix/scripts/system.scm | 10 | ||||
| -rw-r--r-- | guix/ui.scm | 55 |
3 files changed, 68 insertions, 16 deletions
diff --git a/doc/guix.texi b/doc/guix.texi index a4aa1b67fab..a97436cc0c1 100644 --- a/doc/guix.texi +++ b/doc/guix.texi | |||
| @@ -5995,6 +5995,25 @@ For the @code{vm-image} and @code{disk-image} actions, create an image | |||
| 5995 | of the given @var{size}. @var{size} may be a number of bytes, or it may | 5995 | of the given @var{size}. @var{size} may be a number of bytes, or it may |
| 5996 | include a unit as a suffix (@pxref{Block size, size specifications,, | 5996 | include a unit as a suffix (@pxref{Block size, size specifications,, |
| 5997 | coreutils, GNU Coreutils}). | 5997 | coreutils, GNU Coreutils}). |
| 5998 | |||
| 5999 | @item --on-error=@var{strategy} | ||
| 6000 | Apply @var{strategy} when an error occurs when reading @var{file}. | ||
| 6001 | @var{strategy} may be one of the following: | ||
| 6002 | |||
| 6003 | @table @code | ||
| 6004 | @item nothing-special | ||
| 6005 | Report the error concisely and exit. This is the default strategy. | ||
| 6006 | |||
| 6007 | @item backtrace | ||
| 6008 | Likewise, but also display a backtrace. | ||
| 6009 | |||
| 6010 | @item debug | ||
| 6011 | Report the error and enter Guile's debugger. From there, you can run | ||
| 6012 | commands such as @code{,bt} to get a backtrace, @code{,locals} to | ||
| 6013 | display local variable values, and more generally inspect the program's | ||
| 6014 | state. @xref{Debug Commands,,, guile, GNU Guile Reference Manual}, for | ||
| 6015 | a list of available debugging commands. | ||
| 6016 | @end table | ||
| 5998 | @end table | 6017 | @end table |
| 5999 | 6018 | ||
| 6000 | Note that all the actions above, except @code{build} and @code{init}, | 6019 | Note that all the actions above, except @code{build} and @code{init}, |
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm index 277f31f6f46..b6d7d0d045c 100644 --- a/guix/scripts/system.scm +++ b/guix/scripts/system.scm | |||
| @@ -383,6 +383,9 @@ Build the operating system declared in FILE according to ACTION.\n")) | |||
| 383 | 383 | ||
| 384 | (show-build-options-help) | 384 | (show-build-options-help) |
| 385 | (display (_ " | 385 | (display (_ " |
| 386 | --on-error=STRATEGY | ||
| 387 | apply STRATEGY when an error occurs while reading FILE")) | ||
| 388 | (display (_ " | ||
| 386 | --image-size=SIZE for 'vm-image', produce an image of SIZE")) | 389 | --image-size=SIZE for 'vm-image', produce an image of SIZE")) |
| 387 | (display (_ " | 390 | (display (_ " |
| 388 | --no-grub for 'init', do not install GRUB")) | 391 | --no-grub for 'init', do not install GRUB")) |
| @@ -422,6 +425,10 @@ Build the operating system declared in FILE according to ACTION.\n")) | |||
| 422 | (option '(#\V "version") #f #f | 425 | (option '(#\V "version") #f #f |
| 423 | (lambda args | 426 | (lambda args |
| 424 | (show-version-and-exit "guix system"))) | 427 | (show-version-and-exit "guix system"))) |
| 428 | (option '("on-error") #t #f | ||
| 429 | (lambda (opt name arg result) | ||
| 430 | (alist-cons 'on-error (string->symbol arg) | ||
| 431 | result))) | ||
| 425 | (option '("image-size") #t #f | 432 | (option '("image-size") #t #f |
| 426 | (lambda (opt name arg result) | 433 | (lambda (opt name arg result) |
| 427 | (alist-cons 'image-size (size->number arg) | 434 | (alist-cons 'image-size (size->number arg) |
| @@ -514,7 +521,8 @@ Build the operating system declared in FILE according to ACTION.\n")) | |||
| 514 | (action (assoc-ref opts 'action)) | 521 | (action (assoc-ref opts 'action)) |
| 515 | (system (assoc-ref opts 'system)) | 522 | (system (assoc-ref opts 'system)) |
| 516 | (os (if file | 523 | (os (if file |
| 517 | (read-operating-system file) | 524 | (load* file %user-module |
| 525 | #:on-error (assoc-ref opts 'on-error)) | ||
| 518 | (leave (_ "no configuration file specified~%")))) | 526 | (leave (_ "no configuration file specified~%")))) |
| 519 | 527 | ||
| 520 | (dry? (assoc-ref opts 'dry-run?)) | 528 | (dry? (assoc-ref opts 'dry-run?)) |
diff --git a/guix/ui.scm b/guix/ui.scm index d590eef0407..7490de080c5 100644 --- a/guix/ui.scm +++ b/guix/ui.scm | |||
| @@ -43,6 +43,8 @@ | |||
| 43 | #:use-module (ice-9 match) | 43 | #:use-module (ice-9 match) |
| 44 | #:use-module (ice-9 format) | 44 | #:use-module (ice-9 format) |
| 45 | #:use-module (ice-9 regex) | 45 | #:use-module (ice-9 regex) |
| 46 | #:autoload (system repl repl) (start-repl) | ||
| 47 | #:autoload (system repl debug) (make-debug stack->vector) | ||
| 46 | #:replace (symlink) | 48 | #:replace (symlink) |
| 47 | #:export (_ | 49 | #:export (_ |
| 48 | N_ | 50 | N_ |
| @@ -51,7 +53,6 @@ | |||
| 51 | leave | 53 | leave |
| 52 | make-user-module | 54 | make-user-module |
| 53 | load* | 55 | load* |
| 54 | report-load-error | ||
| 55 | warn-about-load-error | 56 | warn-about-load-error |
| 56 | show-version-and-exit | 57 | show-version-and-exit |
| 57 | show-bug-report-information | 58 | show-bug-report-information |
| @@ -146,7 +147,8 @@ messages." | |||
| 146 | modules) | 147 | modules) |
| 147 | module)) | 148 | module)) |
| 148 | 149 | ||
| 149 | (define (load* file user-module) | 150 | (define* (load* file user-module |
| 151 | #:key (on-error 'nothing-special)) | ||
| 150 | "Load the user provided Scheme source code FILE." | 152 | "Load the user provided Scheme source code FILE." |
| 151 | (define (frame-with-source frame) | 153 | (define (frame-with-source frame) |
| 152 | ;; Walk from FRAME upwards until source location information is found. | 154 | ;; Walk from FRAME upwards until source location information is found. |
| @@ -158,6 +160,14 @@ messages." | |||
| 158 | frame | 160 | frame |
| 159 | (loop (frame-previous frame) frame))))) | 161 | (loop (frame-previous frame) frame))))) |
| 160 | 162 | ||
| 163 | (define (error-string frame args) | ||
| 164 | (call-with-output-string | ||
| 165 | (lambda (port) | ||
| 166 | (apply display-error frame port (cdr args))))) | ||
| 167 | |||
| 168 | (define tag | ||
| 169 | (make-prompt-tag "user-code")) | ||
| 170 | |||
| 161 | (catch #t | 171 | (catch #t |
| 162 | (lambda () | 172 | (lambda () |
| 163 | ;; XXX: Force a recompilation to avoid ABI issues. | 173 | ;; XXX: Force a recompilation to avoid ABI issues. |
| @@ -170,11 +180,14 @@ messages." | |||
| 170 | 180 | ||
| 171 | ;; Hide the "auto-compiling" messages. | 181 | ;; Hide the "auto-compiling" messages. |
| 172 | (parameterize ((current-warning-port (%make-void-port "w"))) | 182 | (parameterize ((current-warning-port (%make-void-port "w"))) |
| 173 | ;; Give 'load' an absolute file name so that it doesn't try to | 183 | (call-with-prompt tag |
| 174 | ;; search for FILE in %LOAD-PATH. Note: use 'load', not | 184 | (lambda () |
| 175 | ;; 'primitive-load', so that FILE is compiled, which then allows us | 185 | ;; Give 'load' an absolute file name so that it doesn't try to |
| 176 | ;; to provide better error reporting with source line numbers. | 186 | ;; search for FILE in %LOAD-PATH. Note: use 'load', not |
| 177 | (load (canonicalize-path file)))))) | 187 | ;; 'primitive-load', so that FILE is compiled, which then allows us |
| 188 | ;; to provide better error reporting with source line numbers. | ||
| 189 | (load (canonicalize-path file))) | ||
| 190 | (const #f)))))) | ||
| 178 | (lambda _ | 191 | (lambda _ |
| 179 | ;; XXX: Errors are reported from the pre-unwind handler below, but | 192 | ;; XXX: Errors are reported from the pre-unwind handler below, but |
| 180 | ;; calling 'exit' from there has no effect, so we call it here. | 193 | ;; calling 'exit' from there has no effect, so we call it here. |
| @@ -182,31 +195,43 @@ messages." | |||
| 182 | (rec (handle-error . args) | 195 | (rec (handle-error . args) |
| 183 | ;; Capture the stack up to this procedure call, excluded, and pass | 196 | ;; Capture the stack up to this procedure call, excluded, and pass |
| 184 | ;; the faulty stack frame to 'report-load-error'. | 197 | ;; the faulty stack frame to 'report-load-error'. |
| 185 | (let* ((stack (make-stack #t handle-error)) | 198 | (let* ((stack (make-stack #t handle-error tag)) |
| 186 | (depth (stack-length stack)) | 199 | (depth (stack-length stack)) |
| 187 | (last (and (> depth 0) (stack-ref stack 0))) | 200 | (last (and (> depth 0) (stack-ref stack 0))) |
| 188 | (frame (frame-with-source | 201 | (frame (frame-with-source |
| 189 | (if (> depth 1) | 202 | (if (> depth 1) |
| 190 | (stack-ref stack 1) ;skip the 'throw' frame | 203 | (stack-ref stack 1) ;skip the 'throw' frame |
| 191 | last)))) | 204 | last)))) |
| 192 | (report-load-error file args frame))))) | 205 | |
| 206 | (report-load-error file args frame) | ||
| 207 | |||
| 208 | (case on-error | ||
| 209 | ((debug) | ||
| 210 | (newline) | ||
| 211 | (display (_ "entering debugger; type ',bt' for a backtrace\n")) | ||
| 212 | (start-repl #:debug (make-debug (stack->vector stack) 0 | ||
| 213 | (error-string frame args) | ||
| 214 | #f))) | ||
| 215 | ((backtrace) | ||
| 216 | (newline (current-error-port)) | ||
| 217 | (display-backtrace stack (current-error-port))) | ||
| 218 | (else | ||
| 219 | #t)))))) | ||
| 193 | 220 | ||
| 194 | (define* (report-load-error file args #:optional frame) | 221 | (define* (report-load-error file args #:optional frame) |
| 195 | "Report the failure to load FILE, a user-provided Scheme file, and exit. | 222 | "Report the failure to load FILE, a user-provided Scheme file. |
| 196 | ARGS is the list of arguments received by the 'throw' handler." | 223 | ARGS is the list of arguments received by the 'throw' handler." |
| 197 | (match args | 224 | (match args |
| 198 | (('system-error . _) | 225 | (('system-error . _) |
| 199 | (let ((err (system-error-errno args))) | 226 | (let ((err (system-error-errno args))) |
| 200 | (leave (_ "failed to load '~a': ~a~%") file (strerror err)))) | 227 | (report-error (_ "failed to load '~a': ~a~%") file (strerror err)))) |
| 201 | (('syntax-error proc message properties form . rest) | 228 | (('syntax-error proc message properties form . rest) |
| 202 | (let ((loc (source-properties->location properties))) | 229 | (let ((loc (source-properties->location properties))) |
| 203 | (format (current-error-port) (_ "~a: error: ~a~%") | 230 | (format (current-error-port) (_ "~a: error: ~a~%") |
| 204 | (location->string loc) message) | 231 | (location->string loc) message))) |
| 205 | (exit 1))) | ||
| 206 | ((error args ...) | 232 | ((error args ...) |
| 207 | (report-error (_ "failed to load '~a':~%") file) | 233 | (report-error (_ "failed to load '~a':~%") file) |
| 208 | (apply display-error frame (current-error-port) args) | 234 | (apply display-error frame (current-error-port) args)))) |
| 209 | (exit 1)))) | ||
| 210 | 235 | ||
| 211 | (define (warn-about-load-error file args) ;FIXME: factorize with ↑ | 236 | (define (warn-about-load-error file args) ;FIXME: factorize with ↑ |
| 212 | "Report the failure to load FILE, a user-provided Scheme file, without | 237 | "Report the failure to load FILE, a user-provided Scheme file, without |
