mirror of
https://gitlab.com/vindarel/ciel.git
synced 2026-01-30 04:11:24 -08:00
scripting: register and call built-in scripts by name
This commit is contained in:
parent
3c371c9a81
commit
0d95880caa
7 changed files with 109 additions and 61 deletions
54
README.org
54
README.org
|
|
@ -215,62 +215,26 @@ See more in [[docs/README.md][the documentation]].
|
|||
|
||||
NOTE: this is brand new! Expect limitations and changes.
|
||||
|
||||
Get the =ciel= binary and call it with a .lisp file:
|
||||
Get the =ciel= binary and call it with your .lisp script:
|
||||
|
||||
#+begin_src bash
|
||||
$ ciel script.lisp
|
||||
#+end_src
|
||||
|
||||
An example script:
|
||||
Call built-in scripts:
|
||||
|
||||
#+begin_src lisp
|
||||
;; Start your script with this to access all CIEL goodies:
|
||||
(in-package :ciel-user)
|
||||
|
||||
;; We have access to the STR library:
|
||||
(print (str:join "-" (list "I" "am" "a" "lisper")))
|
||||
|
||||
;; We have access to the DICT notation for hash-tables:
|
||||
(print "testing dict:")
|
||||
(print (dict :a 1 :b 2))
|
||||
|
||||
;; format! prints on standard output and flushes the streams.
|
||||
(format! t "cmd?")
|
||||
|
||||
;; We can run shell commands:
|
||||
(cmd:cmd "ls")
|
||||
|
||||
(format! t "Let's define an alias to run shell commands with '!'. This gives: ")
|
||||
(defalias ! #'cmd:cmd)
|
||||
(! "pwd")
|
||||
|
||||
;; In cas of an error, we can ask for a CIEL toplevel REPL:
|
||||
(handler-case
|
||||
(error "oh no")
|
||||
(error (c)
|
||||
(format! t "An error occured: ~a" c)
|
||||
(format! t "Here's a CIEL top level REPL: ")
|
||||
(sbcli::repl :noinform t)))
|
||||
#+begin_src bash
|
||||
$ ciel --script simpleHTTPserver 9000
|
||||
#+end_src
|
||||
|
||||
Output:
|
||||
or
|
||||
|
||||
#+begin_src txt
|
||||
"I-am-a-lisper"
|
||||
"testing dict:"
|
||||
|
||||
(dict
|
||||
:A 1
|
||||
:B 2
|
||||
)
|
||||
cmd? ABOUT.org ciel ciel-core
|
||||
bin docs src
|
||||
[…]
|
||||
Let's define an alias to run shell commands with '!'. This gives:
|
||||
/home/vindarel/projets/ciel
|
||||
ciel-user>
|
||||
#+begin_src bash
|
||||
$ ciel -s quicksearch colors
|
||||
#+end_src
|
||||
|
||||
See [[https://ciel-lang.github.io/CIEL/#/scripting][the documentation]].
|
||||
|
||||
** Shell REPL
|
||||
|
||||
Run =ciel= with no arguments:
|
||||
|
|
|
|||
11
ciel.asd
11
ciel.asd
|
|
@ -139,7 +139,16 @@
|
|||
:components ((:file "repl")
|
||||
(:file "scripting")
|
||||
(:file "shell-utils")
|
||||
(:file "repl-utils"))
|
||||
(:file "repl-utils")
|
||||
|
||||
;; I define them here, for good practice (for me),
|
||||
;; but I don't use them.
|
||||
;; static-file is important, otherwise the scripts would be run.
|
||||
(:module "src/scripts"
|
||||
:components
|
||||
((:static-file "quicksearch")
|
||||
(:static-file "simpleHTTPserver")))
|
||||
)
|
||||
|
||||
;; Build a binary with Deploy, ship foreign libraries (and ignore libssl).
|
||||
:defsystem-depends-on (:deploy) ;; need to (ql:quickload "deploy") before building.
|
||||
|
|
|
|||
|
|
@ -2,12 +2,20 @@
|
|||
|
||||
> Note: this is brand new! Expect limitations and changes.
|
||||
|
||||
Get the `ciel` binary and call it with a .lisp file:
|
||||
Get the `ciel` binary and call it with your .lisp script:
|
||||
|
||||
```
|
||||
$ ciel script.lisp
|
||||
```
|
||||
|
||||
(or `./script.lisp`, see below)
|
||||
|
||||
Call built-in scripts:
|
||||
|
||||
```
|
||||
$ ciel --script simpleHTTPserver 9000
|
||||
```
|
||||
|
||||
An example script:
|
||||
|
||||
```lisp
|
||||
|
|
@ -20,7 +28,7 @@ An example script:
|
|||
(format! t "Hello ~a!~&" name))
|
||||
|
||||
;; Access CLI args:
|
||||
(hello (second (uiop:command-line-arguments)))
|
||||
(hello (second uiop:*command-line-arguments*))
|
||||
|
||||
;; We have access to the DICT notation for hash-tables:
|
||||
(print "testing dict:")
|
||||
|
|
@ -70,7 +78,9 @@ ciel-user>
|
|||
|
||||
## Command line arguments
|
||||
|
||||
Access them with `(uiop:command-line-arguments)`.
|
||||
Access them with `uiop:*command-line-arguments`.
|
||||
|
||||
This list of arguments can be modified by us. You can always check the original list with `(uiop:command-line-arguments)`.
|
||||
|
||||
|
||||
## Executable file and shebang line
|
||||
|
|
@ -145,17 +155,23 @@ $ ciel -e "(-> (http:get \"https://fakestoreapi.com/products/1\") (json:read-jso
|
|||
)
|
||||
```
|
||||
|
||||
## Other scripts
|
||||
## Built-in scripts
|
||||
|
||||
Call built-in scripts with `--script` or `-s`.
|
||||
|
||||
### Simple HTTP server
|
||||
|
||||
```
|
||||
$ ciel -s simpleHTTPserver 9000
|
||||
```
|
||||
|
||||
see `src/scripts/simpleHTTPserver.lisp` in the CIEL repository.
|
||||
|
||||
~~~lisp
|
||||
(in-package :ciel-user)
|
||||
|
||||
;; CLI args: the script name, an optional port number.
|
||||
(defparameter *port* (or (parse-integer (second (uiop:command-line-arguments)))
|
||||
(defparameter *port* (or (ignore-errors (parse-integer (second uiop:*command-line-arguments*)))
|
||||
8000))
|
||||
|
||||
(defvar *acceptor* (make-instance 'hunchentoot:easy-acceptor
|
||||
|
|
@ -169,7 +185,8 @@ see `src/scripts/simpleHTTPserver.lisp` in the CIEL repository.
|
|||
(sleep most-positive-fixnum)
|
||||
;; Catch a C-c and quit gracefully.
|
||||
(sb-sys:interactive-interrupt ()
|
||||
(format! t "Bye!")))
|
||||
(format! t "Bye!")
|
||||
(hunchentoot:stop *acceptor*)))
|
||||
~~~
|
||||
|
||||
Given you have an `index.html` file:
|
||||
|
|
@ -224,7 +241,7 @@ Search for Lisp libraries on Quicklisp, Cliki and Github.
|
|||
see `src/scripts/quicksearch.lisp`.
|
||||
|
||||
```lisp
|
||||
$ ciel src/scripts/quicksearch.lisp color
|
||||
$ ciel -s quicksearch color
|
||||
|
||||
SEARCH-RESULTS: "color"
|
||||
=======================
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
|
||||
(in-package :ciel)
|
||||
|
||||
(defparameter *scripts* (dict)
|
||||
"Available scripts.
|
||||
Hash-table: file name (sans extension) -> file content (string).")
|
||||
|
||||
(defun maybe-ignore-shebang (in)
|
||||
"If this file starts with #!, delete the shebang line,
|
||||
so we can LOAD the file.
|
||||
|
|
@ -40,6 +44,34 @@
|
|||
(error (c)
|
||||
(format! *error-output* "~a" c))))
|
||||
|
||||
|
||||
(defun register-builtin-scripts ()
|
||||
"Find available scripts in src/scripts, register them in *SCRIPTS*.
|
||||
Call this before creating the CIEL binary."
|
||||
;; We save the file's content as a string.
|
||||
;; We will run them with LOAD (and an input stream from the string).
|
||||
;;
|
||||
;; Example:
|
||||
;;
|
||||
;; (load (make-string-input-stream (str:from-file "src/scripts/simpleHTTPserver.lisp")))
|
||||
(loop for file in (uiop:directory-files "src/scripts/")
|
||||
if (equal "lisp" (pathname-type file))
|
||||
do (format t "~t scripts: registering ~a~&" (pathname-name file))
|
||||
(setf (gethash (pathname-name file) *scripts*)
|
||||
(str:from-file file))))
|
||||
|
||||
(defun run-script (name)
|
||||
"If NAME is registered in *SCRIPTS*, run this script."
|
||||
(bind (((:values content exists) (gethash name *scripts*)))
|
||||
(cond
|
||||
((and exists (str:blankp content)
|
||||
(format *error-output* "uh the script ~s has no content?~&" name)))
|
||||
((not exists)
|
||||
(format *error-output* "The script ~s was not found.~&" name))
|
||||
(t
|
||||
;; Run it!
|
||||
(load (make-string-input-stream content))))))
|
||||
|
||||
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ciel-user
|
||||
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
|
@ -118,6 +150,18 @@
|
|||
|
||||
(return-from main))
|
||||
|
||||
;; --script / -s : run scripts by name.
|
||||
;; They are registered by name in the binary.
|
||||
;; Ideas:
|
||||
;; - look for scripts in specified directories.
|
||||
((member arg '("--script" "-s") :test #'equal)
|
||||
(pop args)
|
||||
(setf arg (first args))
|
||||
;; ditch the "-s" option, must not be seen by the script.
|
||||
(pop uiop:*command-line-arguments*)
|
||||
(run-script arg)
|
||||
(return-from main))
|
||||
|
||||
;; LOAD some file.lisp
|
||||
;; Originally, the goal of the scripting capabilities. The rest are details.
|
||||
((and arg
|
||||
|
|
@ -143,3 +187,10 @@
|
|||
(error (c)
|
||||
(format! *error-output* "Unexpected error: ~a~&" c)
|
||||
(return-from main)))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;; top-level for binary construction.
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(format t "~&Registering built-in scripts in src/scripts/ …~&")
|
||||
(register-builtin-scripts)
|
||||
|
|
|
|||
3
src/scripts/README.md
Normal file
3
src/scripts/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
- it is better to use `uiop:*command-line-arguments*` instead of `(uiop:command-line-arguments)`. The latter always get the original full list, but when calling `ciel -s` we need to pop the arguments list, to ditch the `-s`.
|
||||
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
(in-package :ciel-user)
|
||||
|
||||
(unless (second (uiop:command-line-arguments))
|
||||
(unless (second uiop:*command-line-arguments*)
|
||||
(format! t "Quicksearch: search for Lisp libraries on Quicklisp, Cliki and Github.~&")
|
||||
(format! t "Usage: ciel quicksearch.lisp keyword~&")
|
||||
(uiop:quit))
|
||||
|
||||
(quicksearch:? (second (uiop:command-line-arguments)) :ud) ;; url and details.
|
||||
(quicksearch:? (second uiop:*command-line-arguments*) :ud) ;; url and details.
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@
|
|||
(in-package :ciel-user)
|
||||
|
||||
;; CLI args: the script name, an optional port number.
|
||||
(defparameter *port* (or (parse-integer (second (uiop:command-line-arguments)))
|
||||
8000))
|
||||
(defparameter *port* (or (ignore-errors (parse-integer (second uiop:*command-line-arguments*)))
|
||||
9000))
|
||||
|
||||
(defvar *acceptor* (make-instance 'hunchentoot:easy-acceptor
|
||||
:document-root "./"
|
||||
:port *port*))
|
||||
(defparameter *acceptor* (make-instance 'hunchentoot:easy-acceptor
|
||||
:document-root "./"
|
||||
:port *port*))
|
||||
(hunchentoot:start *acceptor*)
|
||||
|
||||
;; Serve static assets under a static/ directory (optional).
|
||||
|
|
@ -26,4 +26,8 @@
|
|||
(handler-case
|
||||
(sleep most-positive-fixnum)
|
||||
(sb-sys:interactive-interrupt ()
|
||||
(format! t "Bye!")))
|
||||
(format! t "Bye!")
|
||||
(hunchentoot:stop *acceptor*))
|
||||
(error ()
|
||||
(format! t "An error occured. Quitting.")
|
||||
(hunchentoot:stop *acceptor*)))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue