sellout/external-program

Support for pty

Opened this issue · 10 comments

SBCL has a :pty keyword for run-program, which make it possible to talk to other REPL like program possible, for example, python, psql, sqlite, etc. Although it's not in CCL and ECL, but maybe possible implement in a similar way by calling c functions fork, execvp like SBCL does.
I think it's a useful feature. It's of course possible to use these interpreter's low level c library, but need a lot of effort, like library RCL, LTK). Talk to interpreter to directly is a less efficient but quick way. Is this task possible (run a external python, talk to it interactively in CL) in current external-program in current external-program? Thank you

I'm not entirely sure what you're asking.

It seems sbcl's sb-ext:run-program does accept the keyword :pty but other run-program implementations do not. So if you rely on that feature, you'll end up with sbcl-specific code. You could then use one of the following interfaces for asynchronous process spawning

  • sbcl's sb-ext:run-program :wait nil or
  • external-program's start or
  • uiop's launch-program;

since each one will accept the :pty keyword (the latter two will just pass it through to the former) but each solution will be just as unportable. So if your question is if somebody's provided something like external-program:start or uiop:launch-program with a portable :pty keyword argument then I'm afraid the answer is no.

Thank you. Are you interested in adding a portable :pty support. I'll have a try and send you a PR if so. I looked at SBCL's implementation for this, I think it can be implement in every CFFI supported CL.

That's a surprisingly difficult question, to be honest. Maybe a year ago, external-program's run/start and uiop's run-program/launch-program each had their upsides and downsides. I've then put effort into improving the latter (since uiop comes bundled with asdf, one can safely assume that any common lisp installation ships it); the result is that I'm not currently aware of anything external-program handles in a portable fashion and uiop does not, and thus see no reason to base any new code on the former rather than the latter.

That said, when I looked e.g. into the issue of controlling the environment that a process is spawned in, I found it impossible to come up with a portable solution (which is why that is something uiop's run-program/launch-program has no support for): Some common lisp implementations come with a run-program functionality whose :env or :environment argument replaces the environment, for some the list of arguments is added to the environment, for some the time at which the change takes effect is different (i.e.: some use the PATH after setting the environment for program-lookup while others do not...).

The reason I'm saying this for is: If (edit: and only if) you have reasonable hope of coming up with a solution that will work on typical common lisp implementations (abcl, allegro cl, ccl, clisp, cmucl, ecl, lispworks, mkcl, sbcl... except maybe clisp, that's rather dusty) then I encourage you by all means to put a reasonable amount of time into it and submit a PR (again, preferably to asdf, not here) -- the community would be thankful I'm sure.

Unfortunately I cannot be of much help because my health is a disaster, as a result of which I also have not be doing much with common lisp for a while. I'd do my best to provide feedback and code review, though (and I wouldn't be surprised if @rpgoldman and @fare would, too).

fare commented

Right now, uiop:run-program passes the arguments passed to it, with overrides, to the underlying run-program, so you can add your own, if they make sense (maybe it would be better instead to take an extra argument for extra arguments to pass to the underlying run-program, but that's not how it currently is).

If the pty feature requires a subtle modification of arguments actually passed by uiop:launch-program, then that's harder, at requires modification of UIOP. But we accept patches: https://gitlab.common-lisp.net/asdf/asdf/merge_requests

Finally got some time to continue working on this. For CCL, this option is simply ignored (and it's also mentioned in ccl doc currently this option is not implemented):
https://github.com/Clozure/ccl/blob/master/level-1/linux-files.lisp#L1460

fare commented

@epipping is, sadly, deceased this year.

If you submit a patch to UIOP to support the feature on implementations that have it and throws an error if a use is attempted on other implementations, it will be gladly accepted.

Ideally, I would like UIOP to be good enough that external-program could be simply a deprecated wrapper around it.

I agree with @fare here. 1. I am sadly writing more elisp than CL these days, as my career has moved in a different direction; and 2. I support @fare’s efforts to reduce duplication and shore up single solutions to various problems in the CL world.

I’m happy to accept patches to external-program, but I would rather see it replaced by UIOP. I wonder if there’s a term to use prior to “deprecated” that means something like “currently still useful, but it’d be better to add new features to UIOP rather than fix external-program.” Maybe “deprioritized”? I could add something to the README to point people toward UIOP.

Also, I’m saddened to hear that @epipping has passed.

I'm so sorry to hear @epipping has passed. Looks reasonable for me to submit a patch to uiop. Thanks.