org-babel: Never throw away standard error

* lisp/ob-eval.el (org-babel-eval-error-notify): Do not insert
superfluous whitespace.
* lisp/ob-eval.el (org-babel-eval): Show standard error even if the
command exits with a zero code.
* testing/lisp/test-ob-shell.el(
ob-shell/standard-output-after-success,
ob-shell/standard-output-after-failure,
ob-shell/error-output-after-success,
ob-shell/error-output-after-failure,
ob-shell/error-output-after-failure-multiple,
ob-shell/exit-code,
ob-shell/exit-code-multiple
): Add tests to avoid regressions.
This commit is contained in:
Rudolf Adamkovič 2022-10-26 13:35:26 +02:00 committed by Ihor Radchenko
parent 2924c77848
commit f7b16402e6
No known key found for this signature in database
GPG Key ID: 6470762A7DA11D8B
2 changed files with 108 additions and 21 deletions

View File

@ -40,39 +40,44 @@
(with-current-buffer buf
(goto-char (point-max))
(save-excursion
(insert stderr)
(unless (bolp) (insert "\n"))
(insert (format "[ Babel evaluation exited with code %S ]\n" exit-code))))
(insert stderr)
(insert (format "[ Babel evaluation exited with code %S ]" exit-code))))
(display-buffer buf))
(message "Babel evaluation exited with code %S" exit-code))
(defun org-babel-eval (command query)
"Run COMMAND on QUERY.
Return standard output produced by COMMAND. If COMMAND exits
with a non-zero code or produces error output, show it with
`org-babel-eval-error-notify'.
Writes QUERY into a temp-buffer that is processed with
`org-babel--shell-command-on-region'. If COMMAND succeeds then return
its results, otherwise display STDERR with
`org-babel-eval-error-notify'."
`org-babel--shell-command-on-region'."
(let ((error-buffer (get-buffer-create " *Org-Babel Error*")) exit-code)
(with-current-buffer error-buffer (erase-buffer))
(with-temp-buffer
(insert query)
(setq exit-code
(org-babel--shell-command-on-region
command error-buffer))
(if (or (not (numberp exit-code)) (> exit-code 0))
(progn
(with-current-buffer error-buffer
(org-babel-eval-error-notify exit-code (buffer-string)))
(save-excursion
(when (get-buffer org-babel-error-buffer-name)
(with-current-buffer org-babel-error-buffer-name
(unless (derived-mode-p 'compilation-mode)
(compilation-mode))
;; Compilation-mode enforces read-only, but Babel expects the buffer modifiable.
(setq buffer-read-only nil))))
;; Return output, if any.
(buffer-string))
(buffer-string)))))
(org-babel--shell-command-on-region
command error-buffer))
(let ((stderr (with-current-buffer error-buffer (buffer-string))))
(if (or (not (numberp exit-code))
(> exit-code 0)
(not (string-empty-p stderr)))
(progn
(org-babel-eval-error-notify exit-code stderr)
(save-excursion
(when (get-buffer org-babel-error-buffer-name)
(with-current-buffer org-babel-error-buffer-name
(unless (derived-mode-p 'compilation-mode)
(compilation-mode))
;; Compilation-mode enforces read-only, but
;; Babel expects the buffer modifiable.
(setq buffer-read-only nil))))
;; Return output, if any.
(buffer-string))
(buffer-string))))))
(defun org-babel-eval-read-file (file)
"Return the contents of FILE as a string."

View File

@ -170,6 +170,88 @@ ob-comint.el, which was not previously tested."
"#+BEGIN_SRC sh :results table\necho 'I \"want\" it all'\n#+END_SRC"
(org-babel-execute-src-block)))))
;;; Standard output
(ert-deftest ob-shell/standard-output-after-success ()
"Test standard output after exiting with a zero code."
(should (= 1
(org-babel-execute:sh
"echo 1" nil))))
(ert-deftest ob-shell/standard-output-after-failure ()
"Test standard output after exiting with a non-zero code."
(should (= 1
(org-babel-execute:sh
"echo 1; exit 2" nil))))
;;; Standard error
(ert-deftest ob-shell/error-output-after-success ()
"Test that standard error shows in the error buffer, alongside the
exit code, after exiting with a zero code."
(should
(string= "1
[ Babel evaluation exited with code 0 ]"
(progn (org-babel-eval-wipe-error-buffer)
(org-babel-execute:sh
"echo 1 >&2" nil)
(with-current-buffer org-babel-error-buffer-name
(buffer-string))))))
(ert-deftest ob-shell/error-output-after-failure ()
"Test that standard error shows in the error buffer, alongside the
exit code, after exiting with a non-zero code."
(should
(string= "1
[ Babel evaluation exited with code 2 ]"
(progn (org-babel-eval-wipe-error-buffer)
(org-babel-execute:sh
"echo 1 >&2; exit 2" nil)
(with-current-buffer org-babel-error-buffer-name
(buffer-string))))))
(ert-deftest ob-shell/error-output-after-failure-multiple ()
"Test that multiple standard error strings show in the error
buffer, alongside multiple exit codes."
(should
(string= "1
[ Babel evaluation exited with code 2 ]
3
[ Babel evaluation exited with code 4 ]"
(progn (org-babel-eval-wipe-error-buffer)
(org-babel-execute:sh
"echo 1 >&2; exit 2" nil)
(org-babel-execute:sh
"echo 3 >&2; exit 4" nil)
(with-current-buffer org-babel-error-buffer-name
(buffer-string))))))
;;; Exit codes
(ert-deftest ob-shell/exit-code ()
"Test that the exit code shows in the error buffer after exiting
with a non-zero return code."
(should
(string= "[ Babel evaluation exited with code 1 ]"
(progn (org-babel-eval-wipe-error-buffer)
(org-babel-execute:sh
"exit 1" nil)
(with-current-buffer org-babel-error-buffer-name
(buffer-string))))))
(ert-deftest ob-shell/exit-code-multiple ()
"Test that multiple exit codes show in the error buffer after
exiting with a non-zero return code multiple times."
(should
(string= "[ Babel evaluation exited with code 1 ]
[ Babel evaluation exited with code 2 ]"
(progn (org-babel-eval-wipe-error-buffer)
(org-babel-execute:sh
"exit 1" nil)
(org-babel-execute:sh
"exit 2" nil)
(with-current-buffer org-babel-error-buffer-name
(buffer-string))))))
(provide 'test-ob-shell)