run-program in another directory [duplicate] - common-lisp

Suppose I have a directory A, and subdirectory B. I cd into A and launch lisp. In that lisp process, I would like to launch a Python subprocess where Python sees B as its current working directory. The lisp process needs to have cwd in A, and the python process should have cwd in B. How do I do this in a cross-platform, simple way?
I'm looking for a solution that works with CCL and SBCL (probably using 'run-program function), and works for Windows, Linux, and OS X.
I looked at the CCL run-program documentation, and I didn't see a way to change the cwd of the launched process.
I looked at Python command-line arguments, and I didn't see one that would change the cwd of the python process.
I thought about a run-program call for 'cd B; python ...', but I'm not sure how that would work, since it's really running two programs; cd, and then python.
The Python code is being provided as input (as a file), so I cannot change any of that code (by adding an os.chdir() call or similar).
A python wrapper file that launches the python input file as a subprocess isn't ideal, because I'm sending stdin and listening to stdout of the python process launched by lisp. Adding another subprocess in between lisp and the python process that evals the input file means I'd need to do a lot of stout/stdin relaying, and I have a feeling that this would be brittle.
krzysz00's approach worked very well. Since the directory change is handled in lisp, before the python process is launched, this approach will work for launching other processes in different subdirectories (not just python).
For documentation, here's my code using krzsz00's approach that worked for SBCL & CCL. Note that it uses Hoyte's defmacro! macro, from Let Over Lambda, to easily avoid unwanted variable capture:
#+:SBCL
(defun cwd (dir)
(sb-posix:chdir dir))
(defun getcwd ()
#+SBCL (sb-unix:posix-getcwd)
#+CCL (current-directory))
(defmacro! with-cwd (dir &body body)
`(let ((,g!cwd (getcwd)))
(unwind-protect (progn
(cwd ,dir)
,#body)
(cwd ,g!cwd))))
Usage:
(with-cwd "./B"
(run-program ...))

To run external programs (like your python process portably) see external-program. To change the current working directory, use this slightly modified (public domain) function cwd from the file http://files.b9.com/lboot/utils.lisp, which is reproduced below.
(defun cwd (&optional dir)
"Change directory and set default pathname"
(cond
((not (null dir))
(when (and (typep dir 'logical-pathname)
(translate-logical-pathname dir))
(setq dir (translate-logical-pathname dir)))
(when (stringp dir)
(setq dir (parse-namestring dir)))
#+allegro (excl:chdir dir)
#+clisp (#+lisp=cl ext:cd #-lisp=cl lisp:cd dir)
#+(or cmu scl) (setf (ext:default-directory) dir)
#+cormanlisp (ccl:set-current-directory dir)
#+(and mcl (not openmcl)) (ccl:set-mac-default-directory dir)
#+openmcl (ccl:cwd dir)
#+gcl (si:chdir dir)
#+lispworks (hcl:change-directory dir)
#+sbcl (sb-posix:chdir dir)
(setq cl:*default-pathname-defaults* dir))
(t
(let ((dir
#+allegro (excl:current-directory)
#+clisp (#+lisp=cl ext:default-directory #-lisp=cl lisp:default-directory)
#+(or cmu scl) (ext:default-directory)
#+sbcl (sb-unix:posix-getcwd/)
#+cormanlisp (ccl:get-current-directory)
#+lispworks (hcl:get-working-directory)
#+mcl (ccl:mac-default-directory)
#-(or allegro clisp cmu scl cormanlisp mcl sbcl lispworks) (truename ".")))
(when (stringp dir)
(setq dir (parse-namestring dir)))
dir))))
Combining these two functions, the code you want is:
(cwd #p"../b/")
(external-program:start "python" '("file.py") :output *pythins-stdout-stream* :input *pythons-stdin-stream*)
(cwd #p"../a/")
This will cd to B, run the python process as if by python file.py &, send the python process's stdin/stdout to the specified streams (look at the external-program documentation for more details), and finally execute another cwd that returns the lisp process to A. If the lisp process should wait until the python process is finished, use external-program:run instead of external-program:start.

I ended up writing krzysz00's suggestion up into a package that can be found here.
Then someone pointed out that UIOP comes with getcwd and chdir. If you have a fairly recent lisp, UIOP should come included with your edition of asdf.

I dont know what lisp is but could this work?
import subprocess
subprocess.Popen('python myscript.py', cwd='B')
http://docs.python.org/library/subprocess.html

Related

Don't know how to require sb-cltl2

I'm trying to run an executable with an Hunchentoot server and I'm getting (after an unusual high CPU usage):
<INFO> [17:55:14] weblocks/server server.lisp (start) -
Starting weblocks WEBLOCKS/SERVER::PORT: 40001
WEBLOCKS/SERVER::SERVER-TYPE: :HUNCHENTOOT DEBUG: T
debugger invoked on a SB-INT:EXTENSION-FAILURE in thread
#<THREAD "main thread" RUNNING {1008C1EA13}>:
Don't know how to REQUIRE sb-cltl2.
Do you have any idea what's going on ? It works correctly on Slime where I use the start function.
(sbcl manual: http://www.sbcl.org/manual/#Customization-Hooks-for-Users)
In the main entry point, I try to capture the running thread so that I keep the server running on the foreground (my notes). This pattern worked with another clack-based web framework.
(defun start ()
(weblocks/debug:on)
(weblocks/server:start :port *port*))
(defun main ()
(defvar *port* (find-port:find-port))
(start)
(handler-case (bt:join-thread (find-if (lambda (th)
(search "hunchentoot" (bt:thread-name th)))
(bt:all-threads)))
(#+sbcl sb-sys:interactive-interrupt
#+ccl ccl:interrupt-signal-condition
#+clisp system::simple-interrupt-condition
#+ecl ext:interactive-interrupt
#+allegro excl:interrupt-signal
() (progn
(format *error-output* "Aborting.~&")
(uiop:quit 1))
;; for others, unhandled errors (we might want to do the same).
(error (c) (format t "Woops, an unknown error occured:~&~a~&" c)))))
Or any indication of what could be the cause ?
Thanks again.
(I'm using 40ants' weblocks:reblocks branch)
SBCL Debian 1.2.4
edit I tried
export SBCL_HOME=/usr/local/lib/sbcl/
I build with
build:
$(LISP) --quit \
--eval '(ql:quickload "foo")' \
--eval '(require :sb-cltl2)' \
--eval '(asdf:make :foo)'
=>
fatal error encountered in SBCL pid 25248(tid 140737353910016):
can't load .core for different runtime, sorry
Welcome to LDB, a low-level debugger for the Lisp runtime environment.
ldb>
The following environment failed:
export SBCL_HOME=/usr/local/lib/sbcl/
The error message tells us the following:
can't load .core for different runtime, sorry
Apparently the SBCL you ran used the given SBCL_HOME to find its core file, but failed due to the core being generated by different version SBCL.
A quick look at SBCL's source (starting from require) shows that the underlying function #'SB-INT:SBCL-HOMEDIR-PATHNAME is called to determine the installation path.
It looks like the one installed from the Debian package was installed in /usr/lib/sbcl/. The core file was easily found when starting Slime. You also had another version of SBCL in ~/.roswell/, but I guess you also ran ros install which installed it under /usr/local/lib/sbcl (/usr/local/ is for software that is not managed by the system).
Starting the roswell one when setting SBCL_HOME to the directory of the Debian one provoked the error about the incompatible core file (I guess).
What remains suprising is that (SB-INT:SBCL-HOMEDIR-PATHNAME) returns nil when starting your main function.

Installing CLOCC & packages

The comment by sds at Saving CLOS objects provides a reference to a Common Lisp Open Code Collection (CLOCC) file (closio.lisp) for printably reading & writing CLOS objects. Instructions for installing the software are at Installation of CLOCC. However, not having previously used CLOCC, I would like some additional guidance in setting things up for reading/writing CLOS objects. Here are the additions to my init file (.clinit) so far:
(in-package :cl-user)
(setq *clocc-root* "D:\\clocc\\")
(load "D:\\clocc.fasl")
(load
(compile-file ;warns about |make|::COMPILED-FILE-P being undefined
(translate-logical-pathname
"clocc:src;defsystem;defsystem")))
(dolist (s '("clocc:src;cllib;base" "clocc:src;port;sys"))
(mk:add-registry-location (translate-logical-pathname s)))
Instructions for what to add next appreciated.
The instructions were obsolete. Sorry.
The installation instructions now say (I removed the systems you don't need):
(compile-file "c:/gnu/clocc/clocc") ; or whatever ...
(load *)
;; * load the defsystem facility
;; most lisps come with "asdf"; if this fails, get it yourself from
;; https://common-lisp.net/project/asdf/
(require "asdf")
;; * compile some systems
(asdf:compile-system "port")
(asdf:compile-system "cllib")
...
You will need to follow the asdf instructions:
$ mkdir -p ~/.config/common-lisp/source-registry.conf.d/
$ echo '(:tree "c:/gnu/clocc/")' > asdf.conf

How can you use parameters in sbcl (common-lisp), for sb-ext:run-program?

I'm trying to call an external shell command in common-lisp, via SBCL's sb-ext:run-program.
Documentation about this run-program command, can be found here:
http://sbcl.org/manual/index.html
in the section
7.7.3 Running external programs
That page, does not contain examples. I figured out how to use it, by checking this page:
stackoverflow examples for sb-ext:run-program
This is what I'm trying to do...
First, I define a variable for a parameter:
(defconstant *a-argument* "-lh")
Then I call a command:
(sb-ext:run-program "C:\\Program Files (x86)\\Gow\\bin\\ls.exe"
'(*a-argument*)
:output *standard-output*)
It gives me the following error:
debugger invoked on a TYPE-ERROR in thread
#<THREAD "main thread" RUNNING {100299C8F3}>:
The value
*A-ARGUMENT*
is not of type
SEQUENCE
However, if I call it like this:
(sb-ext:run-program "C:\\Program Files (x86)\\Gow\\bin\\ls.exe"
'("-lh")
:output *standard-output*)
then it works. The only difference is using "-lh" directly, instead of *a-argument*.
So the question I have is:
What do I need to do, to make the run-program call work, with a variable in the parameter list?
Extra info:
windows32 2.6.1 7601 i686-pc Intel unknown MinGW
SBCL 1.3.8
But I also tested this on FreeBSD 10.1 and there I have the same problem.
The answer was given by jkiiski:
I needed to change this call:
(sb-ext:run-program "C:\\Program Files (x86)\\Gow\\bin\\ls.exe"
'(*a-argument*)
:output *standard-output*)
To this call:
(sb-ext:run-program "C:\\Program Files (x86)\\Gow\\bin\\ls.exe"
(list *a-argument*)
:output *standard-output*)

SBCL: Deploying Hunchentoot application as executable

I started playing with SBCL Common Lisp and want to develop a small web application using Hunchentoot. For easy deployment I planned to save everything in a binary using sb-ext:save-lisp-and-die as I can live with the big output size.
For the executable you need to supply a toplevel function. The problem is that the program exits when the toplevel function returns. I tried to start Hunchentoot from the executable, but the program ended after two seconds.
How can I wait until Hunchentoot was shut down (from inside a request) before stopping the program? Can I do something like join the Hunchentoot acceptor thread? Or can I even include the REPL into the executable to be able to do live debugging?
(ql:quickload :hunchentoot)
(use-package :hunchentoot)
(defun main ()
(hunchentoot:start-server :port 8082)
(sb-thread:join-thread (find-if
(lambda (th)
(string= (sb-thread:thread-name th) "hunchentoot-listener-1"))
(sb-thread:list-all-threads))))
No explicit code is required to give you access to a REPL if you keep a terminal open (perhaps via GNU Screen). Send Ctrl+C to the terminal to break into the debugger.
;;; I simply use sleep to yield the main thread.
;;; To start the server while developing I use
;;; start-server. For deployment I use the main
;;; function.
(defun start-server ()
(hunchentoot:start
(make-instance 'hunchentoot:easy-acceptor :port 8000)))
(defun main()
(start-server)
(sleep #xffffffff))

Need help running thread SBCL

I am working some lisp code on sbcl in order to run function in mode daemon.
The problem is when I use the function sb-thred:make-thread, for instance as follow:
(sb-thread:make-thread (lambda () (progn (sleep 1) (when t (print "background action")))))
I get the following error message:
Not supported in unithread builds. [Condition of type SIMPLE-ERROR]
What is wrong ? ... thanks for help.
SBCL has threads disabled by default on Mac OS X. To check if SBCL is build with threads run in the repl
(member :sb-thread *features*)
If not, compile it from source (using your current SBCL). From the INSTALL
sh make.sh --with-sb-thread

Resources