From 7001ed80e5fd146f6acf586b3cf3ef20bbba04e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rudolf=20Adamkovi=C4=8D?= Date: Wed, 26 Oct 2022 13:35:26 +0200 Subject: [PATCH] ob-shell: 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. --- lisp/ob-eval.el | 47 +++++++++++--------- testing/lisp/test-ob-shell.el | 82 +++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 21 deletions(-) diff --git a/lisp/ob-eval.el b/lisp/ob-eval.el index e1278bbad..af9283c0a 100644 --- a/lisp/ob-eval.el +++ b/lisp/ob-eval.el @@ -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." diff --git a/testing/lisp/test-ob-shell.el b/testing/lisp/test-ob-shell.el index 4c00faa49..7aa45cc8a 100644 --- a/testing/lisp/test-ob-shell.el +++ b/testing/lisp/test-ob-shell.el @@ -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) -- 2.38.1