add file-notify, add webapp script

[ci skip]
This commit is contained in:
vindarel 2023-04-24 15:55:28 +02:00
parent ad63aae024
commit b65572e3b9
7 changed files with 196 additions and 4 deletions

View file

@ -87,6 +87,15 @@ Debian system):
libmagic-dev libc6-dev gcc # from magicffi
On Linux:
inotify-tools
On MacOS:
fsevent
## With Quicklisp
You need a Lisp implementation and Quicklisp installed.

View file

@ -44,6 +44,7 @@
:cl-json-pointer/synonyms
:dissect
:fset
:file-notify ;; needs inotify (linux) or fsevent (macos)
:generic-cl
;; web

View file

@ -735,6 +735,23 @@ But typing `os:` and TAB in SLIME doesn't help very much with
auto-discovery, so we also added a `/os` local nickname, so that we
see the available symbols earlier in the autocompletion list.
We include [file-notify](https://github.com/shinmera/file-notify) to watch changes to files (using `inotify` on Linux and `fsevent` on MacOS). It is available with the `notify:` local nickname.
~~~lisp
(notify:watch "webapp.lisp")
(notify:with-events (file change :timeout T)
;; Print the available list of events:
;; (print (list file change))
(when (equal change :close-write)
(format! t "~%~%Reloading ~a…~&" file)
(handler-case
(ciel::load-without-shebang "webapp.lisp")
(reader-error ()
;; Catch some READ errors, such as parenthesis not closed, etc.
(format! t "~%~%read error, waiting for change…~&"))))))
~~~
## Regular expressions
@ -945,12 +962,23 @@ Learn more with:
We include
[Quicksearch](https://github.com/lisp-maintainers/quicksearch), a
simple search utility for Common Lisp libraries:
simple search utility for Common Lisp libraries that searches on
GitHub, Quickdocs and Cliki.
You can call it with CIEL's binary:
$ ciel -s quicksearch ciel
or by calling its wrapper script directly:
$ quicksearch.lisp ciel # according you have it in your PATH
or from the Lisp REPL:
(qs:? "ciel" :u)
this will search on GitHub, Quickdocs and Cliki for "ciel", and it
will print the URL of search results.
this will search for the "ciel" keyword and it will print the URL of
search results (`:u`).
```
SEARCH-RESULTS: "ciel"

View file

@ -356,7 +356,7 @@ $ ciel -e "(-> (http:get \"https://fakestoreapi.com/products/1\") (json:read-jso
Call built-in scripts with `--script <scriptname>` or `-s`.
Call `ciel --scripts` to list the available scripts.
Call `ciel --scripts` to list the available ones.
Those are for demo purposes and are subject to evolve. Ideas and contributions welcome.
@ -467,3 +467,75 @@ We welcome more capable, expanded scripts!
---
Now, let us iron out the details ;)
### Simple web app with routes
See [`scr/scripts/webapp.lisp`](https://github.com/ciel-lang/CIEL/blob/master/src/scripts/webapp.lisp) for inspiration.
This creates one route on `/` with an optional `name` parameter. Go to `localhost:4567/?name=you` and see.
```lisp
#!/usr/bin/env ciel
;;;
;;; Run with:
;;; $ ./webapp.lisp
;;;
(in-package :ciel-user)
(routes:defroute route-root "/" (&get name)
(format nil "Hello ~a!" (or name (os:getenv "USER") "lisper")))
(defvar *server* nil)
(defun start-webapp ()
(setf *server* (make-instance 'routes:easy-routes-acceptor :port 4567))
(hunchentoot:start *server*))
(defun stop-webapp ()
(hunchentoot:stop *server*))
#+ciel
(progn
(start-webapp)
(format t "~&App started on localhost:4567…~&")
(sleep most-positive-fixnum))
```
At this point you'll certainly want to live-reload your changes.
### Auto-reload
In this snippet:
[`webapp-notify.lisp`](https://github.com/ciel-lang/CIEL/blob/master/src/scripts/webapp-notify.lisp),
we use the [file-notify](https://github.com/shinmera/file-notify)
library (shipped in CIEL) to watch write changes to our lisp file, and load
it again.
This allows you to have a dumb "live reload" workflow with a simple editor and a terminal.
> WARNING: This does NOT take advantage of Common Lisp's image-based-development features at all. Install yourself a Common Lisp IDE to enjoy the interactive debugger, compiling one function at a time, trying things out in the REPL, autocompletion, code navigation…
> INFO: you need `inotify` on Linux and `fsevent` on MacOS.
~~~lisp
(defun simple-auto-reload ()
(notify:watch "webapp.lisp")
(notify:with-events (file change :timeout T)
;; Print the available list of events:
;; (print (list file change))
(when (equal change :close-write)
(format! t "~%~%Reloading ~a…~&" file)
(handler-case
(ciel::load-without-shebang "webapp.lisp")
(reader-error ()
;; Catch some READ errors, such as parenthesis not closed, etc.
(format! t "~%~%read error, waiting for change…~&"))))))
#+ciel
(unless *server*
(start-webapp)
(format t "~&App started on localhost:4567…~&")
(simple-auto-reload)
(sleep most-positive-fixnum))
~~~

View file

@ -15,6 +15,7 @@
(:os :uiop/os)
;; This other uiop module is always useful:
(:filesystem :uiop/filesystem)
(:notify :org.shirakumo.file-notify)
(:alex :alexandria)
(:csv :cl-csv)

56
src/scripts/webapp-notify.lisp Executable file
View file

@ -0,0 +1,56 @@
#!/usr/bin/env ciel
;;;
;;; Run with:
;;; $ ./webapp-notify.lisp
;;;
;;; Watch this file for write events and load & compile it again.
;;; This redefines our web routes, so we can develop our app in a simple interactive way.
;;;
;;; If you are doing that, you'll want to setup a proper dev environment to enjoy full Common Lisp image-based development.
(in-package :ciel-user)
(routes:defroute route-root "/" (&get name)
(format nil "Hello ~a!" (or name (os:getenv "USER") "lisper")))
(routes:defroute route-hello "/hello" ()
(format nil "Hello :)"))
;; Try adding new routes.
;; (gotcha: give them unique names)
(defvar *server* nil)
(defun start-webapp ()
(unless *server*
(setf *server* (make-instance 'routes:easy-routes-acceptor :port 4567))
(hunchentoot:start *server*)))
(defun stop-webapp ()
(hunchentoot:stop *server*))
(defun dumb-auto-reload ()
"Watch this file for write events and load & compile it again.
This redefines our web routes, so we can develop our app in a simple interactive way.
If you are doing that, you'll want to setup a proper dev environment to enjoy full Common Lisp image-based development."
(format! t "~&Watching webapp.lisp…")
(notify:watch "webapp.lisp")
(notify:with-events (file change :timeout T)
;; list of events:
;; (print (list file change))
(when (equal change :close-write)
(format! t "~%~%Reloading ~a…~&" file)
(handler-case
(ciel::load-without-shebang "webapp.lisp")
(reader-error ()
;; READ errors, parenthesis not closed, etc. Wait for the developer.
(format! t "~%~%read error, waiting for change…~&"))))))
#+ciel
(unless *server*
(start-webapp)
(format t "~&App started on localhost:4567…~&")
(dumb-auto-reload)
(sleep most-positive-fixnum))

25
src/scripts/webapp.lisp Executable file
View file

@ -0,0 +1,25 @@
#!/usr/bin/env ciel
;;;
;;; Run with:
;;; $ ./webapp.lisp
;;;
(in-package :ciel-user)
(routes:defroute route-root "/" (&get name)
(format nil "Hello ~a!" (or name (os:getenv "USER") "lisper")))
(defvar *server* nil)
(defun start-webapp ()
(setf *server* (make-instance 'routes:easy-routes-acceptor :port 4567))
(hunchentoot:start *server*))
(defun stop-webapp ()
(hunchentoot:stop *server*))
#+ciel
(progn
(start-webapp)
(format t "~&App started on localhost:4567…~&")
(sleep most-positive-fixnum))