b85a3b5c35649170228e0ab0fa5af6e4da2454fb
[projects/qitab/inferior-shell.git] / README
1 INFERIOR-SHELL
2
3 This CL library allows you to spawn local or remote processes and shell pipes.
4 It lets me use CL in many cases where I would previously write shell scripts.
5 The name is a pun, in that this library can both
6 let you spawn inferior (children processes) shells, and
7 serve itself as an inferior (not so featureful) shell.
8 Because so many features of a shell are missing,
9 inferior-shell only brings down the low-hanging fruits of shell scripting;
10 yet CL is such a better programming language than the shell
11 (or other "scripting" languages) that it is already a great pleasure
12 to be able to write things in CL rather than in these languages.
13 More features will come, and/or you can use other CL libraries as a complement.
14
15 Inferior-shell recognizes a small domain-specific language to describe
16 commands or pipelines of commands, and some functions to actually run
17 these pipelines either locally or remotely (via ssh).
18 It will implicitly invoke ssh when asked to run a command on a remote host;
19 for best results, be sure to have passphrase-less access to these hosts
20 via e.g. ssh-agent.
21
22 The name inferior-shell was suggested by Michael Livshin,
23 as inspired by the equivalent notion in GNU Emacs.
24
25 Example use of inferior-shell, from the rpm system:
26 (defun rpms-installed (&key (packagenames t) host)
27   (run/lines
28    `(pipe (rpm -qa)
29           ,@(unless (eq packagenames t)
30               `((egrep ("^(" ,@(loop :for (name . more) :on packagenames
31                                  :collect name :when more :collect "|")
32                              ")-[^-]+(-[^-]+)?$")))))
33    :host host))
34
35
36 ==== Limitations ====
37
38 By default, inferior-shell uses asdf-driver:run-program
39 as its universal execution backend, and has its limitations,
40 which are as follows.
41
42 First, inferior-shell at this point only supports
43 synchronous execution of sub-processes.
44 For asynchronous execution, please use IOlib or executor.
45 IOlib requires C compilation and linking, and may or may not support Windows.
46 executor only supports select implementations.
47 A future extension to inferior-shell may use IOlib as a backend.
48
49 Second, there is currently limited support for input redirection.
50 The only possible input redirection is from /dev/null
51 or by inheriting the parent's standard input
52 when running in :interactive mode.
53 However, using shell redirection, you can also redirect input from a file,
54 or from a numbered file descriptor (except 0, 1, 2).
55
56 Finally, supported platforms at this time include:
57 ABCL, Allegro, CLISP, ClozureCL, CMUCL, ECL, LispWorks, RMCL, SBCL, SCL, XCL.
58 Platforms NOT (yet) supported include:
59 CormanLisp (untested), GCL (untested), Genera (unimplemented), MKCL (untested).
60 On supported platforms, inferior-shell works on both Unix and Windows.
61
62
63 ==== Exported Functionality ====
64
65 The inferior-shell library creates a package INFERIOR-SHELL,
66 that exports the following macros and functions:
67
68 PARSE-PROCESS-SPEC SPEC
69   parse an expression in the process-spec mini-language into
70   objects specifying a pipeline of processes to be executed.
71   See the PROCESS-SPEC mini-language below.
72
73 PRINT-PROCESS-SPEC SPEC &OPTIONAL OUTPUT
74   print a process specification to given OUTPUT
75   into a portable form usable by a Unix shell.
76   OUTPUT is as per FORMAT's stream output argument,
77   defaults to NIL for returning the result as a string.
78   SPEC can be a parsed PROCESS-SPEC object,
79   a CONS to be parsed by PARSE-PROCESS-SPEC,
80   or a string for a process-spec that has already been formatted.
81
82 *CURRENT-HOST-NAMES*
83   a variable, a list of strings, the aliases for the localhost.
84   You may need to initialize it if the defaults don't suffice.
85
86 CURRENT-HOST-NAME-P X
87   a function, returns true if X is a string member of *CURRENT-HOST-NAMES*
88
89 INITIALIZE-CURRENT-HOST-NAMES
90   function that initializes the *CURRENT-HOST-NAMES*
91   with "localhost" and the results from $(hostname -s) and $(hostname -f).
92
93 RUN CMD &KEY ON-ERROR TIME SHOW HOST OUTPUT
94   RUN will execute the given command CMD, which can be
95   a CONS to be parsed by PARSE-PROCESS-SPEC,
96   a PROCESS-SPEC object already parsed,
97   or a string to be passed to a Unix shell.
98   ON-ERROR specifies behavior in case the command doesn't successfully exit
99   with exit code 0, as per FARE-UTILS's ERROR-BEHAVIOR provided with
100   (if a function, invoke it, if a string, issue an error with it,
101   otherwise return it as is).
102   TIME is a boolean which if true causes the execution to be timed as per TIME.
103   SHOW is a boolean which if true causes a message to be sent
104   to the *TRACE-OUTPUT* before execution.
105   HOST is either NIL (execute on localhost) or a string specifying a host
106   on which to run the command using ssh if
107   it's not an alias for localhost as recognized by CURRENT-HOST-NAME-P
108   (be sure to have passphraseless  login using ssh-agent).
109   The INPUT, OUTPUT and ERROR-OUTPUT arguments are as for UIOP:RUN-PROGRAM,
110   except that they default to NIL, T, T respectively instead of NIL, NIL, NIL.
111   In particular, OUTPUT is as per UIOP:SLURP-OUTPUT-STREAM one of
112   NIL for no output (redirect to /dev/null),
113   a stream for itself,
114   T (default) for the current *standard-output*,
115   :INTERACTIVE for inheriting the parent process's stdout,
116   :LINES for returning one result per line,
117   :STRING for returning the output as one big string,
118   :STRING/STRIPPED is like :STRING
119   but strips any line-ending at the end of the results,
120   just like a shell's `cmd` or $(cmd) would, and
121   more options are accepted and you can define your own, as per
122   asdf-driver's slurp-input-stream protocol.
123   On Windows, RUN will not succeed for pipes, only for simple commands.
124   On Unix, simple commands on localhost are executed directly, but
125   remote commands and pipes are executed by spawning a shell.
126
127 RUN/NIL CMD &KEY ON-ERROR TIME SHOW HOST
128   RUN/NIL is a shorthand for RUN with :INPUT :OUTPUT :ERROR-OUTPUT bound to NIL.
129
130 RUN/S CMD &KEY ON-ERROR TIME SHOW HOST
131   RUN/S is a shorthand for RUN with :OUTPUT bound to :STRING,
132   returning as a string what the inferior command sent to its standard output.
133
134 RUN/SS CMD &KEY ON-ERROR TIME SHOW HOST
135   RUN/S is a shorthand for RUN :OUTPUT :STRING/STRIPPED,
136   just like a shell's `cmd` or $(cmd) would do.
137
138 RUN/INTERACTIVE CMD &KEY ON-ERROR TIME SHOW HOST
139   RUN/INTERACTIVE is a shorthand for RUN with :INPUT :OUTPUT :ERROR-OUTPUT
140   all boud to :INTERACTIVE, so you may run commands that interact with users,
141   inheritting the stdin, stdout and stderr of the current process.
142
143 RUN/LINES CMD &KEY ON-ERROR TIME SHOW HOST
144   run/lines is a shorthand for RUN :OUTPUT :LINES,
145   returning as a list of one string per line (stripped of line-ending)
146   what the inferior command sent to its standard output.
147
148 *BACKEND*
149   a variable to choose between backends. Currently, only supported are
150   :AUTO (the default, using asdf-driver:run-program, and
151   spawning a shell unless it's a simple process), and
152   :SBCL (only available on #+(and sbcl sb-thread unix),
153   doesn't need a shell but has some limitations such as
154   only supporting redirection of stdin, stdout, stderr).
155
156
157 ==== THE PROCESS-SPEC MINI-LANGUAGE ====
158
159 This library offers a SEXP syntax to specify processes
160 and pipelines of processes in the manner of Unix shells,
161 including support for file descriptor redirection.
162 Process specifications can be printed,
163 to be executed by a local or remote shell,
164 or directly executed by your Lisp implementation,
165 depending on its capabilities and on the complexity of the pipeline.
166
167 SEXP mini-language
168
169 ;; A process is a pipe or a command
170 process := pipe | or | and | progn | fork | command
171
172 ;; A pipe is a list of processes, each of whose output is connected to the next one's input.
173 pipe := ( pipe process* )
174
175 ;; OR is a list of processes which will be executed in sequence until one returns exit code 0.
176 or := ( or processes )
177
178 ;; AND is a list of processes which will be executed in sequence until one does not return exit code 0.
179 and := ( and processes )
180
181 ;; PROGN is a list of processes which will be executed sequentially.
182 progn := ( progn processes )
183
184 ;; FORK is a list of processes which will be forked and executed in parallel.
185 fork := ( fork processes )
186
187 ;; A command is a list of tokens and redirections.
188 ;; Tokens specify the argv, redirections specify modifications of the inherited file descriptors.
189 command := ( [redirection|token|tokens]* )
190
191 ;; A token is a string, to be used literally,
192 ;; a keyword, to be downcased and prefixed with -- as in :foo ==> "--foo"
193 ;; a symbol, to be downcased, or a list of tokens to be concatenated.
194 token := string | keyword | symbol | (token*)
195
196 ;; A list starting with * is actually to be spliced in the token stream.
197 tokens := (\* [token|tokens]*)
198
199 ;; Redirections mimic those redirections available to a shell, for instance zsh.
200 redirection := (
201  ! fd pathname flags |   ;; open a file with given flags redirect to specified fd
202  < fd? pathname | ;; open a file for input, redirect to specified fd (default: 0)
203  [>|>>|<>|>!|>>!] fd? pathname | ;; open a file for (respectively) output, append, io, output clobbering, append clobbering, redirect to specified fd (default: 1)
204  - fd | <& fd - | >& fd - | ;; close a fd
205  <& - | >& - | ;; close fd 0, respectively fd 1.
206  <& fd fd | >& fd fd | ;; redirect fds: the left one is the new number, the right one the old number.
207  >& pn | >&! | ;; redirect both fd 1 and 2 to pathname (respectively, clobbering)
208  >>& pn | >>&! ) ;; redirect both fd 1 and 2 to append to pathname (respectively, clobbering)
209
210 Note that these are all exported symbols from the INFERIOR-SHELL package,
211 except that a few of them are also inherited from COMMON-LISP: < > -
212 Therefore the other ones will only work if you either
213 use the INFERIOR-SHELL package or
214 use a package prefix INFERIOR-SHELL: where appropriate.
215
216 A SEXP in the minilanguage can be parsed with parse-process-spec,
217 into an object of class process-spec.
218 print-process-spec will print a process-spec object;
219 in this context, a string represents itself (assuming it's already a printed process spec),
220 and a cons is a specification in the minilanguage to be parsed with parse-process-spec first.
221
222
223 ==== TO DO ====
224
225 Document it.
226
227 Have a complementary inferior-shell-watcher library that uses iolib to spawn
228 pipes locally, and watch the subprocesses as part of the iolib event loop.