~ruther/guix-local

2abcc97fd1867176d5530f988ab34c26530de2c2 — Ludovic Courtès 10 years ago fbb25e5
ui: Auto-compile user code, and improve error reporting.

Reported by Christian Grothoff.

* guix/ui.scm (load*): Add 'frame-with-source'.  Set
  %load-should-auto-compile.  Change error handle to just (exit 1).  Add
  pre-unwind handler to capture the stack and call 'report-load-error'.
  (report-load-error): Add optional 'frame' parameter and pass it to
  'display-error'.
* tests/guix-system.sh: Add "unbound variable" test.
3 files changed, 65 insertions(+), 5 deletions(-)

M .dir-locals.el
M guix/ui.scm
M tests/guix-system.sh
M .dir-locals.el => .dir-locals.el +1 -0
@@ 13,6 13,7 @@
  .
  ((indent-tabs-mode . nil)
   (eval . (put 'eval-when 'scheme-indent-function 1))
   (eval . (put 'call-with-prompt 'scheme-indent-function 1))
   (eval . (put 'test-assert 'scheme-indent-function 1))
   (eval . (put 'test-assertm 'scheme-indent-function 1))
   (eval . (put 'test-equal 'scheme-indent-function 1))

M guix/ui.scm => guix/ui.scm +38 -5
@@ 35,6 35,7 @@
  #:use-module (srfi srfi-11)
  #:use-module (srfi srfi-19)
  #:use-module (srfi srfi-26)
  #:use-module (srfi srfi-31)
  #:use-module (srfi srfi-34)
  #:use-module (srfi srfi-35)
  #:use-module (srfi srfi-37)


@@ 147,18 148,50 @@ messages."

(define (load* file user-module)
  "Load the user provided Scheme source code FILE."
  (define (frame-with-source frame)
    ;; Walk from FRAME upwards until source location information is found.
    (let loop ((frame    frame)
               (previous frame))
      (if (not frame)
          previous
          (if (frame-source frame)
              frame
              (loop (frame-previous frame) frame)))))

  (catch #t
    (lambda ()
      ;; XXX: Force a recompilation to avoid ABI issues.
      (set! %fresh-auto-compile #t)
      (set! %load-should-auto-compile #t)

      (save-module-excursion
       (lambda ()
         (set-current-module user-module)
         (primitive-load file))))
    (lambda args
      (report-load-error file args))))

(define (report-load-error file args)
         ;; Hide the "auto-compiling" messages.
         (parameterize ((current-warning-port (%make-void-port "w")))
           ;; Give 'load' an absolute file name so that it doesn't try to
           ;; search for FILE in %LOAD-PATH.  Note: use 'load', not
           ;; 'primitive-load', so that FILE is compiled, which then allows us
           ;; to provide better error reporting with source line numbers.
           (load (canonicalize-path file))))))
    (lambda _
      ;; XXX: Errors are reported from the pre-unwind handler below, but
      ;; calling 'exit' from there has no effect, so we call it here.
      (exit 1))
    (rec (handle-error . args)
         ;; Capture the stack up to this procedure call, excluded, and pass
         ;; the faulty stack frame to 'report-load-error'.
         (let* ((stack (make-stack #t handle-error))
                (depth (stack-length stack))
                (last  (and (> depth 0) (stack-ref stack 0)))
                (frame (frame-with-source
                        (if (> depth 1)
                            (stack-ref stack 1)   ;skip the 'throw' frame
                            last))))
           (report-load-error file args frame)))))

(define* (report-load-error file args #:optional frame)
  "Report the failure to load FILE, a user-provided Scheme file, and exit.
ARGS is the list of arguments received by the 'throw' handler."
  (match args


@@ 172,7 205,7 @@ ARGS is the list of arguments received by the 'throw' handler."
       (exit 1)))
    ((error args ...)
     (report-error (_ "failed to load '~a':~%") file)
     (apply display-error #f (current-error-port) args)
     (apply display-error frame (current-error-port) args)
     (exit 1))))

(define (warn-about-load-error file args)         ;FIXME: factorize with ↑

M tests/guix-system.sh => tests/guix-system.sh +26 -0
@@ 45,6 45,32 @@ else
fi


# Reporting of unbound variables.

cat > "$tmpfile" <<EOF
(use-modules (gnu))                                   ; 1
(use-service-modules networking)                      ; 2

(operating-system                                     ; 4
  (host-name "antelope")                              ; 5
  (timezone "Europe/Paris")                           ; 6
  (locale "en_US.UTF-8")                              ; 7

  (bootloader (GRUB-config (device "/dev/sdX")))      ; 9
  (file-systems (cons (file-system
                        (device "root")
                        (title 'label)
                        (mount-point "/")
                        (type "ext4"))
                      %base-file-systems)))
EOF

if guix system build "$tmpfile" -n 2> "$errorfile"
then false
else
    grep "$tmpfile:9:.*[Uu]nbound variable.*GRUB-config" "$errorfile"
fi

# Reporting of duplicate service identifiers.

cat > "$tmpfile" <<EOF