Git Product home page Git Product logo

simple-inferiors's Introduction

About Simple-Inferiors

This is a library to allow easy handling of external processes, and primarily to get their output. It handles proper copying of stdout and stderr of the process simultaneously, both in a sequential and parallel fashion. It also features a lazy directory switching mechanism, to avoid running into parallelism problems when having to chdir.

How To

Load simple-inferiors with ASDF or Quicklisp

(ql:quickload :simple-inferiors)

Run a program!

(simple-inferiors:run "bash" '("-c" "for i in `seq 1 10`; do echo $i; done"))

Not very exciting. By default the output is discarded and you only get the exit code. Let's see what it says:

(simple-inferiors:run "bash" '("-c" "for i in `seq 1 10`; do echo $i; done")
                      :output T)

By default the streams will be copied character by character. This allows the most immediate fetching of the output from the process, at the cost of being very CPU intensive. If you can afford it, you may want to switch to a more efficient method, such as copying line by line:

(simple-inferiors:run "bash" '("-c" "for i in `seq 1 10`; do echo $i; done")
                      :output T :copier :line)

The output actually doesn't change for this tiny test case, but the performance can be radically different for larger outputs. You may also pass a number to specify a custom buffer size, or a function to handle the stream copying yourself.

When the stack is unwound, simple-inferiors tries to terminate the external process. By default it will try to ask the process to terminate with 0.1 second delays and then it will try to kill it if it still hasn't terminated. In order to control this stopping, you must supply a different handler to run.

(simple-inferiors:run "bash" '("-c" "sleep 60") 
                      :handler (lambda (c p oi oo ei eo) 
                                 (simple-inferiors:handle-process-sequential c p oi oo ei eo :stop-attempts 100)))

You may also use handle-process-parallel if you would like to use threads to handle the stdout and stderr of the process instead of attempting to read both simultaneously sequentially, or provide your own handler function entirely.

If you need to handle different directories for your process, you can use with-chdir. Note that with-chdir does not actually perform a chdir and instead rebinds *cwd*. The chdir is only performed (if at all necessary) at the very last stage when a process is run. This avoids clashing if parallelism is involved. with-chdir merges the passed location (resolved by location) with the current *cwd*. If *cwd* is NIL (such as at the very beginning), the cwd is used to merge the path. If you need to absolutely definitely perform a chdir, you may use with-exchdir. Note that it will signal an invalid-location-error if changing directory to an inexistent location is attempted.

simple-inferiors's People

Contributors

shinmera avatar

Stargazers

Jonas Rodrigues avatar  avatar ebigram avatar David.Gao avatar NCM avatar modula t. avatar Alexandra Catalina avatar  avatar

Watchers

James Cloos avatar  avatar  avatar  avatar

simple-inferiors's Issues

Does not run on Clozure CL

Seems that Clozure CL has a different UIOP interface.

Undefined function UIOP/DRIVER::LAUNCH-PROGRAM called with arguments 
*** truncated ***
Backtrace:
 0: (SIMPLE-INFERIORS::%START-PROCESS #<Unknown Arguments>)
 1: ((:INTERNAL SIMPLE-INFERIORS:RUN) #<BROADCAST-STREAM #x30200225C41D>)
 2: ((:INTERNAL BORDEAUX-THREADS::BINDING-DEFAULT-SPECIALS))
 3: (CCL::RUN-PROCESS-INITIAL-FORM #<PROCESS scsynth(82) [Active] #x30200223456D> (#<CCL:COMPILED-LEXICAL-CLOSURE (:INTERNAL CCL::%PROCESS-RUN-FUNCTION) #x3020022342DF>))
 4: ((:INTERNAL (CCL::%PROCESS-PRESET-INTERNAL (CCL:PROCESS))) #<PROCESS scsynth(82) [Active] #x30200223456D> (#<CCL:COMPILED-LEXICAL-CLOSURE (:INTERNAL CCL::%PROCESS-RUN-FUNCTION) #x3020022342DF>))
 5: ((:INTERNAL CCL::THREAD-MAKE-STARTUP-FUNCTION))

There's UIOP:RUN-PROGRAM. Not sure if it's identical with the supposed-existing LAUNCH-PROGRAM.

ccl complains

Reader error: No external symbol named "TERMINATE-PROCESS" in package #<Package "UIOP/DRIVER"> .

load process.lisp error

-sbcl (devar process-start-lock (bt:make-lock "Process starting lock"))

should be

-sbcl (defvar process-start-lock (bt:make-lock "Process starting lock"))

Behaviour of with-chdir depends on slashes at the end of the path

This leads to WTF behaviour. Here is an illustration:

POFTHEDAY> (simple-inferiors:with-chdir ("foo/")
             (simple-inferiors:with-chdir ("bar/")
               simple-inferiors:*cwd*))
#P"/Users/art/projects/lisp/lisp-project-of-the-day/foo/bar/"
POFTHEDAY> ;; Now, without slashes
; No values
POFTHEDAY> (simple-inferiors:with-chdir ("foo")
             (simple-inferiors:with-chdir ("bar")
               simple-inferiors:*cwd*))
#P"/Users/art/projects/lisp/lisp-project-of-the-day/bar"

"The name VERBOSE does not designate any package" when reloading without Verbose loaded

I get errors reloading simple-inferiors on a clean Lisp image if it was compiled with Verbose loaded into the image.

CL-USER> (ql:quickload :verbose)
CL-USER> (ql:quickload :simple-inferiors)
;;;; slime-restart-inferior-lisp happens here
CL-USER> (ql:quickload :simple-inferiors)

To load "simple-inferiors":
  Load 1 ASDF system:
    simple-inferiors
; Loading "simple-inferiors"

Error finding package for symbol "LOG":
 The name "VERBOSE" does not designate any package.
   [Condition of type SB-KERNEL:SIMPLE-PACKAGE-ERROR]

Restarts:
 0: [TRY-RECOMPILING] Recompile process and try loading it again
 1: [RETRY] Retry loading FASL for #<CL-SOURCE-FILE "simple-inferiors" "process">.
 2: [ACCEPT] Continue, treating loading FASL for #<CL-SOURCE-FILE "simple-inferiors" "process"> as having been successful.
 3: [RETRY] Retry ASDF operation.
 4: [CLEAR-CONFIGURATION-AND-RETRY] Retry ASDF operation after resetting the configuration.
 5: [RETRY] Retry ASDF operation.
 6: [CLEAR-CONFIGURATION-AND-RETRY] Retry ASDF operation after resetting the configuration.
 7: [ABORT] Give up on "simple-inferiors"
 8: [RETRY] Retry SLIME REPL evaluation request.
 9: [*ABORT] Return to SLIME's top level.
 10: [ABORT] abort thread (#<THREAD "repl-thread" RUNNING {100FAD1DE3}>)

Backtrace:
  0: ((LABELS SB-FASL::AUX-FOP-INTERN :IN "SYS:SRC;CODE;FOP.LISP") 7 #S(SB-FASL::UNDEFINED-PACKAGE :ERROR "The name \"VERBOSE\" does not designate any package.") #S(SB-FASL::FASL-INPUT :STREAM #<SB-SYS:FD-..
  1: (SB-FASL::LOAD-FASL-GROUP #S(SB-FASL::FASL-INPUT :STREAM #<SB-SYS:FD-STREAM for "file /home/phoe/.cache/common-lisp/sbcl-2.0.0-linux-x64/home/phoe/.roswell/lisp/quicklisp/dists/quicklisp/software/simp..
  2: (SB-FASL::LOAD-AS-FASL #<SB-SYS:FD-STREAM for "file /home/phoe/.cache/common-lisp/sbcl-2.0.0-linux-x64/home/phoe/.roswell/lisp/quicklisp/dists/quicklisp/software/simple-inferiors-20190710-git/process...
  3: ((FLET SB-FASL::THUNK :IN LOAD))
  4: (SB-FASL::CALL-WITH-LOAD-BINDINGS #<CLOSURE (FLET SB-FASL::THUNK :IN LOAD) {7FE30B0B170B}> #<SB-SYS:FD-STREAM for "file /home/phoe/.cache/common-lisp/sbcl-2.0.0-linux-x64/home/phoe/.roswell/lisp/quick..
  5: ((FLET SB-FASL::LOAD-STREAM :IN LOAD) #<SB-SYS:FD-STREAM for "file /home/phoe/.cache/common-lisp/sbcl-2.0.0-linux-x64/home/phoe/.roswell/lisp/quicklisp/dists/quicklisp/software/simple-inferiors-201907..
  6: (LOAD #P"/home/phoe/.cache/common-lisp/sbcl-2.0.0-linux-x64/home/phoe/.roswell/lisp/quicklisp/dists/quicklisp/software/simple-inferiors-20190710-git/process.fasl" :VERBOSE NIL :PRINT NIL :IF-DOES-NOT-..
  7: ((LAMBDA NIL :IN UIOP/LISP-BUILD:LOAD*))
  8: (UIOP/UTILITY:CALL-WITH-MUFFLED-CONDITIONS #<CLOSURE (LAMBDA NIL :IN UIOP/LISP-BUILD:LOAD*) {10104AE01B}> ("Overwriting already existing readtable ~S." #(#:FINALIZERS-OFF-WARNING :ASDF-FINALIZERS)))
  9: (UIOP/LISP-BUILD:CALL-WITH-MUFFLED-LOADER-CONDITIONS #<CLOSURE (LAMBDA NIL :IN UIOP/LISP-BUILD:LOAD*) {10104AE01B}>)
 10: (UIOP/LISP-BUILD:LOAD* #P"/home/phoe/.cache/common-lisp/sbcl-2.0.0-linux-x64/home/phoe/.roswell/lisp/quicklisp/dists/quicklisp/software/simple-inferiors-20190710-git/process.fasl")
 11: (ASDF/LISP-ACTION:PERFORM-LISP-LOAD-FASL #<ASDF/LISP-ACTION:LOAD-OP > #<ASDF/LISP-ACTION:CL-SOURCE-FILE "simple-inferiors" "process">)
 12: ((:METHOD ASDF/ACTION:PERFORM (ASDF/LISP-ACTION:LOAD-OP ASDF/LISP-ACTION:CL-SOURCE-FILE)) #<ASDF/LISP-ACTION:LOAD-OP > #<ASDF/LISP-ACTION:CL-SOURCE-FILE "simple-inferiors" "process">) [fast-method]
 13: ((SB-PCL::EMF ASDF/ACTION:PERFORM) #<unused argument> #<unused argument> #<ASDF/LISP-ACTION:LOAD-OP > #<ASDF/LISP-ACTION:CL-SOURCE-FILE "simple-inferiors" "process">)
 14: ((FLET CALL-NEXT-METHOD :IN "/home/phoe/Projects/Lisp/asdf/build/asdf.lisp"))
 15: ((LAMBDA NIL :IN ASDF/ACTION:PERFORM))
 16: ((LAMBDA NIL :IN ASDF/ACTION:CALL-WHILE-VISITING-ACTION))
 17: (ASDF/SESSION:CALL-WITH-ASDF-SESSION #<CLOSURE (LAMBDA NIL :IN ASDF/ACTION:CALL-WHILE-VISITING-ACTION) {10104ADEEB}> :OVERRIDE NIL :KEY NIL :OVERRIDE-CACHE NIL :OVERRIDE-FORCING NIL)
 18: (ASDF/ACTION:CALL-WHILE-VISITING-ACTION #<ASDF/LISP-ACTION:LOAD-OP > #<ASDF/LISP-ACTION:CL-SOURCE-FILE "simple-inferiors" "process"> #<CLOSURE (LAMBDA NIL :IN ASDF/ACTION:PERFORM) {10104ADEBB}>)
 19: ((:METHOD ASDF/ACTION:PERFORM :AROUND (ASDF/OPERATION:OPERATION ASDF/COMPONENT:COMPONENT)) #<ASDF/LISP-ACTION:LOAD-OP > #<ASDF/LISP-ACTION:CL-SOURCE-FILE "simple-inferiors" "process">) [fast-method]
 --more--

A workaround is to (asdf:load-system :simple-inferiors :force t) to recompile the system without any compile-time flags.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.