babel: Provide notification of errors during code execution

This deals with external process :results value mode for R, ruby,
python, perl and clojure: if the shell process has a non-zero exit
code, a buffer containing stderr is displayed.
This commit is contained in:
Dan Davison 2010-03-05 11:29:30 +00:00
parent 4e9a2d4efd
commit ba4d698fa1
6 changed files with 113 additions and 85 deletions

View File

@ -142,18 +142,22 @@ BODY, if RESULT-TYPE equals 'value then return the value of the
last statement in BODY, as elisp."
(if (not session)
;; external process evaluation
(let ((tmp-file (make-temp-file "R-out-functional-results")))
(case result-type
(output
(with-temp-buffer
(insert body)
(org-babel-shell-command-on-region (point-min) (point-max) "R --slave --no-save" 'current-buffer 'replace)
(buffer-string)))
(value
(with-temp-buffer
(insert (format org-babel-R-wrapper-method
body tmp-file (if column-names-p "TRUE" "FALSE")))
(org-babel-shell-command-on-region (point-min) (point-max) "R --no-save"))
(case result-type
(output
(with-temp-buffer
(insert body)
(org-babel-shell-command-on-region (point-min) (point-max) "R --slave --no-save" 'current-buffer 'replace)
(buffer-string)))
(value
(let* ((tmp-file (make-temp-file "R-out-functional-results")) exit-code
(stderr
(with-temp-buffer
(insert (format org-babel-R-wrapper-method
body tmp-file (if column-names-p "TRUE" "FALSE")))
(setq exit-code (org-babel-shell-command-on-region
(point-min) (point-max) "R --no-save" nil 'replace (current-buffer)))
(buffer-string))))
(if (> exit-code 0) (org-babel-error-notify exit-code stderr))
(org-babel-R-process-value-result
(org-babel-import-elisp-from-file (org-babel-maybe-remote-file tmp-file))
column-names-p))))

View File

@ -219,25 +219,27 @@ or nil if \"none\" is specified"
(defun org-babel-clojure-evaluate-external-process (buffer body &optional result-type)
"Evaluate the body in an external process."
(save-window-excursion
(case result-type
(output
(with-temp-buffer
(insert body)
(org-babel-shell-command-on-region
(point-min) (point-max)
(format "%s - " (mapconcat #'identity (org-babel-clojure-babel-clojure-cmd) " "))
'current-buffer 'replace)
(buffer-string)))
(value
(let ((tmp-results-file (make-temp-file "clojure_babel_results_")))
(with-temp-buffer
(insert (format org-babel-clojure-wrapper-method body tmp-results-file tmp-results-file))
(org-babel-shell-command-on-region
(point-min) (point-max)
(format "%s - " (mapconcat #'identity (org-babel-clojure-babel-clojure-cmd) " "))))
(org-babel-clojure-table-or-string
(with-temp-buffer (insert-file-contents (org-babel-maybe-remote-file tmp-results-file)) (buffer-string))))))))
(save-excursion
(let ((cmd (format "%s -" (mapconcat #'identity (org-babel-clojure-babel-clojure-cmd) " "))))
(case result-type
(output
(with-temp-buffer
(insert body)
(org-babel-shell-command-on-region cmd (point-min) (point-max) 'current-buffer 'replace)
(buffer-string)))
(value
(let* ((tmp-file (make-temp-file "org-babel-clojure-results-")) exit-code
(stderr
(with-temp-buffer
(insert
(format org-babel-clojure-wrapper-method body tmp-file tmp-file))
(setq exit-code
(org-babel-shell-command-on-region (point-min) (point-max) cmd nil 'replace (current-buffer)))
(buffer-string))))
(if (> exit-code 0) (org-babel-error-notify exit-code stderr))
(org-babel-clojure-table-or-string
(with-temp-buffer
(insert-file-contents (org-babel-maybe-remote-file tmp-file)) (buffer-string)))))))))
(defun org-babel-clojure-evaluate-session (buffer body &optional result-type)
"Evaluate the body in the context of a clojure session"

View File

@ -92,7 +92,7 @@ BODY, if RESULT-TYPE equals 'value then return the value of the
last statement in BODY, as elisp."
(if (not session)
;; external process evaluation
(save-window-excursion
(save-excursion
(case result-type
(output
(with-temp-buffer
@ -101,20 +101,25 @@ last statement in BODY, as elisp."
(org-babel-shell-command-on-region (point-min) (point-max) "perl" 'current-buffer 'replace)
(buffer-string)))
(value
(let ((tmp-file (make-temp-file "perl-functional-results")))
(with-temp-buffer
(insert
(format
(if (member "pp" result-params)
(error "Pretty-printing not implemented for perl")
org-babel-perl-wrapper-method)
(mapconcat
(lambda (line) (format "\t%s" line))
(split-string
(org-remove-indentation (org-babel-trim body)) "[\r\n]") "\n")
tmp-file))
;; (message "buffer=%s" (buffer-string)) ;; debugging
(org-babel-shell-command-on-region (point-min) (point-max) "perl"))
(let* ((tmp-file (make-temp-file "perl-functional-results")) exit-code
(stderr
(with-temp-buffer
(insert
(format
(if (member "pp" result-params)
(error "Pretty-printing not implemented for perl")
org-babel-perl-wrapper-method)
(mapconcat
(lambda (line) (format "\t%s" line))
(split-string
(org-remove-indentation (org-babel-trim body)) "[\r\n]") "\n")
tmp-file))
;; (message "buffer=%s" (buffer-string)) ;; debugging
(setq exit-code
(org-babel-shell-command-on-region
(point-min) (point-max) "perl" nil 'replace (current-buffer)))
(buffer-string))))
(if (> exit-code 0) (org-babel-error-notify exit-code stderr))
(org-babel-import-elisp-from-file (org-babel-maybe-remote-file tmp-file))))))
;; comint session evaluation
(error "Sessions are not supported for Perl.")))

View File

@ -155,7 +155,7 @@ BODY, if RESULT-TYPE equals 'value then return the value of the
last statement in BODY, as elisp."
(if (not session)
;; external process evaluation
(save-window-excursion
(save-excursion
(case result-type
(output
(with-temp-buffer
@ -164,20 +164,24 @@ last statement in BODY, as elisp."
(org-babel-shell-command-on-region (point-min) (point-max) "python" 'current-buffer 'replace)
(buffer-string)))
(value
(let ((tmp-file (make-temp-file "python-functional-results")))
(with-temp-buffer
(insert
(format
(if (member "pp" result-params)
org-babel-python-pp-wrapper-method
org-babel-python-wrapper-method)
(mapconcat
(lambda (line) (format "\t%s" line))
(split-string
(org-remove-indentation (org-babel-trim body)) "[\r\n]") "\n")
tmp-file))
;; (message "buffer=%s" (buffer-string)) ;; debugging
(org-babel-shell-command-on-region (point-min) (point-max) "python"))
(let* ((tmp-file (make-temp-file "org-babel-python-results-")) exit-code
(stderr
(with-temp-buffer
(insert
(format
(if (member "pp" result-params)
org-babel-python-pp-wrapper-method
org-babel-python-wrapper-method)
(mapconcat
(lambda (line) (format "\t%s" line))
(split-string
(org-remove-indentation (org-babel-trim body)) "[\r\n]") "\n")
tmp-file))
;; (message "buffer=%s" (buffer-string)) ;; debugging
(setq exit-code (org-babel-shell-command-on-region
(point-min) (point-max) "python" nil 'replace (current-buffer)))
(buffer-string))))
(if (> exit-code 0) (org-babel-error-notify exit-code stderr))
(let ((raw (with-temp-buffer
(insert-file-contents (org-babel-maybe-remote-file tmp-file))
(buffer-string))))

View File

@ -159,7 +159,7 @@ BODY, if RESULT-TYPE equals 'value then return the value of the
last statement in BODY, as elisp."
(if (not session)
;; external process evaluation
(save-window-excursion
(save-excursion
(case result-type
(output
(with-temp-buffer
@ -168,13 +168,17 @@ last statement in BODY, as elisp."
(org-babel-shell-command-on-region (point-min) (point-max) "ruby" 'current-buffer 'replace)
(buffer-string)))
(value
(let ((tmp-file (make-temp-file "ruby-functional-results")))
(with-temp-buffer
(insert (format (if (member "pp" result-params)
org-babel-ruby-pp-wrapper-method
org-babel-ruby-wrapper-method) body tmp-file))
;; (message "buffer=%s" (buffer-string)) ;; debugging
(org-babel-shell-command-on-region (point-min) (point-max) "ruby"))
(let* ((tmp-file (make-temp-file "ruby-functional-results")) exit-code
(stderr
(with-temp-buffer
(insert (format (if (member "pp" result-params)
org-babel-ruby-pp-wrapper-method
org-babel-ruby-wrapper-method) body tmp-file))
;; (message "buffer=%s" (buffer-string)) ;; debugging
(setq exit-code
(org-babel-shell-command-on-region (point-min) (point-max) "ruby" nil 'replace (current-buffer)))
(buffer-string))))
(if (> exit-code 0) (org-babel-error-notify exit-code stderr))
(let ((raw (with-temp-buffer
(insert-file-contents (org-babel-maybe-remote-file tmp-file))
(buffer-string))))

View File

@ -1022,6 +1022,14 @@ block but are passed literally to the \"example-block\"."
(nb-add (buffer-substring index (point-max)))))
new-body))
(defun org-babel-error-notify (exit-code stderr)
(message (format "Shell command exited with code %d" exit-code))
(let ((buf (get-buffer-create "*Org-Babel Error Output*")))
(with-current-buffer buf
(goto-char (point-max))
(save-excursion (insert stderr)))
(display-buffer buf)))
(defun org-babel-clean-text-properties (text)
"Strip all properties from text return."
(set-text-properties 0 (length text) nil text) text)
@ -1055,22 +1063,23 @@ This is taken almost directly from `org-read-prop'."
"Read the results located at FILE-NAME into an elisp table. If
the table is trivial, then return it as a scalar."
(let (result)
(with-temp-buffer
(condition-case nil
(progn
(org-table-import file-name nil)
(delete-file file-name)
(setq result (mapcar (lambda (row)
(mapcar #'org-babel-string-read row))
(org-table-to-lisp))))
(error nil)))
(if (null (cdr result)) ;; if result is trivial vector, then scalarize it
(if (consp (car result))
(if (null (cdr (car result)))
(caar result)
result)
(car result))
result)))
(save-window-excursion
(with-temp-buffer
(condition-case nil
(progn
(org-table-import file-name nil)
(delete-file file-name)
(setq result (mapcar (lambda (row)
(mapcar #'org-babel-string-read row))
(org-table-to-lisp))))
(error nil)))
(if (null (cdr result)) ;; if result is trivial vector, then scalarize it
(if (consp (car result))
(if (null (cdr (car result)))
(caar result)
result)
(car result))
result))))
(defun org-babel-string-read (cell)
"Strip nested \"s from around strings in exported R values."