;;;; running.lisp -- functions for running oneliners ;; Copyright (C) 2022 Colin Okay ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU Affero General Public License as ;; published by the Free Software Foundation, either version 3 of the ;; License, or (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU Affero General Public License for more details. ;; You should have received a copy of the GNU Affero General Public License ;; along with this program. If not, see . (in-package :oneliners.cli.running) (defmacro wait-until ((&key (timeout 1) (poll-every 0.01)) &body check) "Run CHECK every POLL-EVERY seconds until either TIMEOUT seconds have passed or CHECK returns non-nil." (let ((clockvar (gensym)) (var (gensym))) `(loop for ,clockvar from 0 by ,poll-every to ,timeout for ,var = (progn ,@check) when ,var return ,var do (sleep ,poll-every) finally (return nil)))) (defun run-with-shell (command &key shell-name await-output-p (output-stream *standard-output*) (error-stream *error-output*)) "run COMMAND, a string, in a fresh shell environment, initialized with SHELL-NAME. The output from the command read line by line and is printed to OUTPUT-STREAM. " (let ((shell (uiop:launch-program shell-name :input :stream :output :stream :error-output :stream))) (let ((shell-input (uiop:process-info-input shell)) (shell-err (uiop:process-info-error-output shell)) (shell-output (uiop:process-info-output shell))) (write-line command shell-input) (finish-output shell-input) (when (and await-output-p (plusp await-output-p)) (loop while (wait-until (:timeout await-output-p :poll-every 0.05) (or (listen shell-err) (listen shell-output))) when (listen shell-output) do (princ (read-char shell-output) output-stream) else do (princ (read-char shell-err) error-stream))))))