Commit 6510db1e authored by Robert P. Goldman's avatar Robert P. Goldman
Browse files

Fixes for UIOP:RUN-PROGRAM on ACL.

On ACL, the :INPUT and :OUTPUT arguments to EXCL:RUN-SHELL-COMMAND take
NIL for the behavior of inheriting input and output handles from the
Lisp process.  These were encoded as T in UIOP:RUN-PROGRAM, instead of
NIL, causing ACL to get errors trying to open T as a file designator.

Added a couple of test cases to test-run-program.script to illustrate
the problem.

Note that this fix does not provide the prescribed behavior for :OUTPUT
NIL (which should take the program's output and throw it on the floor).
There is a TODO in uiop:run-program explaining what's missing.  In
brief, ACL's EXCL:RUN-SHELL-COMMAND does not support this behavior out
of the box, so one would have to capture the program's output, and then
throw it on the floor.
parent 98a32bf0
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -34,6 +34,12 @@
(assert-equal "ok  1" (run-program '("echo" "ok  1") :output :line))
(assert-equal "ok  1" (run-program '("echo" "ok  1") :output :line))
(assert-equal '(:ok 1) (run-program '("echo" ":ok  1") :output :forms))
(assert-equal '(:ok 1) (run-program '("echo" ":ok  1") :output :forms))
(assert-equal (format nil "ok  1~%") (run-program '("echo" "ok  1") :output :string))
(assert-equal (format nil "ok  1~%") (run-program '("echo" "ok  1") :output :string))
;; this test checks for a problem there was in allegro -- :output :interactive
;; would try to open T as a stream for INPUT.
(assert-equal 0 (run-program "true" :force-shell t :output :interactive))
(assert-equal 0 (run-program "true" :force-shell nil :output :interactive))
(assert-equal 1 (run-program "false" :force-shell t :output :interactive :ignore-error-status t))
(assert-equal 1 (run-program "false" :force-shell nil :output :interactive :ignore-error-status t))




;;#+allegro (trace excl:run-shell-command sys:reap-os-subprocess)
;;#+allegro (trace excl:run-shell-command sys:reap-os-subprocess)
+26 −7
Original line number Original line Diff line number Diff line
@@ -247,10 +247,22 @@ return the exit status code of the process that was called.
if it was NIL, the output is discarded;
if it was NIL, the output is discarded;
if it was :INTERACTIVE, the output and the input are inherited from the current process.
if it was :INTERACTIVE, the output and the input are inherited from the current process.


Otherwise, the output will be processed by SLURP-INPUT-STREAM,
Otherwise, OUTPUT should be a value that is a suitable first argument to
using OUTPUT as the first argument, and return whatever it returns,
SLURP-INPUT-STREAM.  In this case, RUN-PROGRAM will create a temporary stream
e.g. using :OUTPUT :STRING will have it return the entire output stream as a string.
for the program output.  The program output, in that stream, will be processed
Use ELEMENT-TYPE and EXTERNAL-FORMAT for the stream passed to the OUTPUT processor."
by SLURP-INPUT-STREAM, according to the using OUTPUT as the first argument.
RUN-PROGRAM will return whatever SLURP-INPUT-STREAM returns.  E.g., using
:OUTPUT :STRING will have it return the entire output stream as a string.  Use
ELEMENT-TYPE and EXTERNAL-FORMAT for the stream passed to the OUTPUT processor."

    ;; TODO: The current version does not honor :OUTPUT NIL on Allegro.  Setting
    ;; the :INPUT and :OUTPUT arguments to RUN-SHELL-COMMAND on ACL actually do
    ;; what :OUTPUT :INTERACTIVE is advertised to do here.  To get the behavior
    ;; specified for :OUTPUT NIL, one would have to grab up the process output
    ;; into a stream and then throw it on the floor.  The consequences of
    ;; getting this wrong seemed so much worse than having excess output that it
    ;; is not currently implemented.

    ;; TODO: specially recognize :output pathname ?
    ;; TODO: specially recognize :output pathname ?
    (declare (ignorable ignore-error-status element-type external-format))
    (declare (ignorable ignore-error-status element-type external-format))
    #-(or abcl allegro clisp clozure cmu cormanlisp ecl gcl lispworks mcl sbcl scl xcl)
    #-(or abcl allegro clisp clozure cmu cormanlisp ecl gcl lispworks mcl sbcl scl xcl)
@@ -292,7 +304,8 @@ Use ELEMENT-TYPE and EXTERNAL-FORMAT for the stream passed to the OUTPUT process
                         (excl:run-shell-command
                         (excl:run-shell-command
                          #+os-unix (coerce (cons (first command) command) 'vector)
                          #+os-unix (coerce (cons (first command) command) 'vector)
                          #+os-windows command
                          #+os-windows command
                          :input interactive :output (or (and pipe :stream) interactive) :wait wait
                          :input nil
                          :output (and pipe :stream) :wait wait
                          #+os-windows :show-window #+os-windows (and (or (null output) pipe) :hide))
                          #+os-windows :show-window #+os-windows (and (or (null output) pipe) :hide))
                         #+clisp
                         #+clisp
                         (flet ((run (f &rest args)
                         (flet ((run (f &rest args)
@@ -379,12 +392,17 @@ Use ELEMENT-TYPE and EXTERNAL-FORMAT for the stream passed to the OUTPUT process
             (redirected-system-command (command out)
             (redirected-system-command (command out)
               (format nil (if (os-unix-p) "exec > ~*~A ; ~2:*~A" "~A > ~A")
               (format nil (if (os-unix-p) "exec > ~*~A ; ~2:*~A" "~A > ~A")
                       (system-command command) (native-namestring out)))
                       (system-command command) (native-namestring out)))
             ;; this is only called if :OUTPUT is NIL or :INTERACTIVE
             (system (command &key interactive)
             (system (command &key interactive)
               (declare (ignorable interactive))
               (declare (ignorable interactive))
               #+(or abcl xcl) (ext:run-shell-command command)
               #+(or abcl xcl) (ext:run-shell-command command)
               #+allegro
               #+allegro
               (excl:run-shell-command
               (excl:run-shell-command
                command :input interactive :output interactive :wait t
                command
                :input nil 
                :output nil
                :error-output :output ; write STDERR to output, too
                :wait t
                #+os-windows :show-window #+os-windows (unless (or interactive (eq output t)) :hide))
                #+os-windows :show-window #+os-windows (unless (or interactive (eq output t)) :hide))
               #+(or clisp clozure cmu (and lispworks os-unix) sbcl scl)
               #+(or clisp clozure cmu (and lispworks os-unix) sbcl scl)
               (process-result (run-program command :pipe nil :interactive interactive) nil)
               (process-result (run-program command :pipe nil :interactive interactive) nil)
@@ -412,6 +430,7 @@ Use ELEMENT-TYPE and EXTERNAL-FORMAT for the stream passed to the OUTPUT process
                                               :element-type element-type
                                               :element-type element-type
                                               #-gcl2.6 :external-format #-gcl2.6 external-format)
                                               #-gcl2.6 :external-format #-gcl2.6 external-format)
                         (slurp-input-stream output stream)))
                         (slurp-input-stream output stream)))
                     ;; OUTPUT is either NIL (discard) or :INTERACTIVE
                     (call-system (system-command command) :interactive interactive)))))
                     (call-system (system-command command) :interactive interactive)))))
      (if (and (not force-shell)
      (if (and (not force-shell)
               #+(or clisp ecl) ignore-error-status
               #+(or clisp ecl) ignore-error-status