If you run the arc server as a thread, you can load in files while it's still running or restart the server without killing the arc process:
; Start the arc server in a thread called t*
arc> (= t* (thread (asv)))
#<thread: t*>
arc> ready to serve port 8080
; Load a file while the server is still running
; Every function and macro in arc.arc is redefined (ellipsized here for brevity)
arc> (load "arc.arc")
*** redefining caar
*** redefining cadr
*** redefining cddr
...
; Stop the server without terminating the arc process by
; breaking the thread
arc> (break-thread t*)
#<void>
arc> user break
=== context ===
/home/evanrmurphy/programas/arc/arc3.1/ac.scm:1040:20: socket-accept
handle-request-1
gs1046
zz
; Restart the server by creating the thread anew
arc> (= t* (thread (asv)))
#<thread: t*>
arc> ready to serve port 8080
I suppose we can sleep and poll the timestamp, but I'm running into a problem, mtime is defined in lib/files.arc,
The way I'm settings things up, my experimental "app" is in a completely isolated folder, and once I'm in there, "lib/files.arc" is no longer in the current directory, how should I go about loading stuff from "lib/"?
For now I only need the 'mtime' function so I just snatched it, but I hope there's a better way of importing standard libs.
Otherwise, here's a little file watcher I just wrote, seems to work with my tiny test case:
(def mtime (path)
" Returns the modification time of the file or directory `path' in
seconds since the epoch. "
($.file-or-directory-modify-seconds path))
(= file-ts* (obj))
(def file-ts-changed (file-name)
(no:is (file-ts* file-name) (mtime file-name)))
(def update-file-ts (file-name)
(= (file-ts* file-name) (mtime file-name)))
; watch file system for updates to file-name
; and run 'delegate' when file is updated
(def watch (file-name delegate)
(update-file-ts file-name)
(while (no (file-ts-changed file-name))
(sleep 2))
(delegate)
(update-file-ts file-name))
(def watch-load (file-name)
(repeat 2 (prn))
(pr "watching " file-name " for changes ..")
(watch file-name
(fn() (load file-name) (pr "reloaded " file-name))))
(watch-load "web.arc")
1. Shouldn't the last line be (watch file-name delegate) so that it continues to watch after the first update? Or should that be optional?
2. It might be a good idea to pass file-name to the delegate. Not strictly necessary, and doesn't give any benefit in this example, but it could mean that you sometimes don't need to use a fn as the delegate. If you didn't want to pr "reloaded" for instance, you could just do (watch file-name load).
3. Is the hash table really necessary? Here is a version without it:
I put the call to watch as the last line inside the file itself.
And the hash table is there because I initially wanted to watch multiple files at the same time. But I suppose if the main file in the web app loads the other files, then it's not needed at all.
The other thing I did is running the (asv) thread only once by checking for an unbound symbol, so that when the file is reloaded it doesn't run the server again.
Ah, so loading the file makes it watch itself. You need to do the load in a thread then?
I still fail to see how the hash table helps since my version above should do exactly the same as yours. I would see the point if you made a thread check all files in the table, and made the first call to watch launch the thread, while subsequent calls just add entries to the table.