emacs tramp over an unreliable connection - r

I want to run R on a remote box under a local Emacs (I do not want to run Emacs on the remote box).
I can run R on a remote host using TRAMP:
(let ((default-directory "/user#remote:~"))
(R))
and everything works fine except that when the connection to remote is lost, R dies. This is no good because this means that I have to re-load all the data into R after restarting it, which takes time.
Is it possible to tell TRAMP to use a persistent terminal? (GNU Screen or tmux or Mosh or dtach)
See also emacs-devel thread tramp:sshx:(screen|tmux).

Here is an alternative approach using dtach:
(defvar R-remote-host "remote-server")
(defvar R-remote-session "R")
(defvar R-remote-directory "~")
(defun R-remote (&optional remote-host session directory)
"Connect to the remote-host's dtach session running R."
(interactive (list
(read-from-minibuffer "R remote host: " R-remote-host)
(read-from-minibuffer "R remote session: " R-remote-session)
(read-from-minibuffer "R remote directory: " R-remote-directory)))
(pop-to-buffer (make-comint (concat "remote-" session)
"ssh" nil "-t" "-t" remote-host
"cd" directory ";"
"dtach" "-A" (concat ".dtach-" session)
"-z" "-E" "-r" "none"
inferior-R-program-name "--no-readline"
inferior-R-args))
(ess-remote (process-name (get-buffer-process (current-buffer))) "R")
(setq comint-process-echoes t))
Call M-x R-remote RET RET RET RET.
It works for me.
PS. The answer to the problem (as opposed to the question as asked) is to use ein with Jupyter.

Here is how to use ESS with R running in a remote screen session:
ssh to the remote host (outside of emacs)
start screen session
detach it
open shell in emacs (M-x shell)
ssh to the remote host again in the emacs shell
resume the screen session (screen -r)
start R
finally attach ESS to the R process using M-x ess-remote in the shell buffer where you started R
There are more details, screenshots, and keybindings in this post http://blog.nguyenvq.com/2010/07/11/using-r-ess-remote-with-screen-in-emacs/

Related

sbcl executable crash when running a hunchentoot server

I want to create a http server with sbcl + hunchentoot. Everything goes well as long as I test the codes in a REPL or run the script file directly, but when I save the core as an executable, the server just crashes every time I try to access the web page of the hunchentoot server.
The testing code is fairly easy, in the server.lisp file, we have:
#!/usr/local/bin/sbcl --script
(require :asdf)
(asdf:load-system :hunchentoot)
(defpackage :http-server
(:use :cl :hunchentoot))
(in-package :http-server)
(defvar *my-acceptor* (make-instance 'easy-acceptor :port 6161))
(defun main ()
(format t "Starting http server on port ~a~%" (acceptor-port *my-acceptor*))
(start *my-acceptor*)
(handler-case
(loop do (sleep 1000))
(condition () nil)))
(defun hello ()
(format nil "Hello, it works!"))
(push
(create-prefix-dispatcher "/hello.html" #'hello)
*dispatch-table*)
;; (sb-ext:save-lisp-and-die "http-server" :toplevel 'main :executable t)
(main)
Now, if I just run the script directly in the terminal, it works flawlessly. The hello.html page can be accessed. Then I change the last two lines to
(sb-ext:save-lisp-and-die "http-server" :toplevel 'main :executable t)
;; (main)
My intention is to run the script again, and it will generate an executable file http-server. Then we have problems.
I start the server by executing the executable file http-server, and every time I access "http://127.0.0.1:6161/hello.html", the http-server process just crashes, with following error messages:
Starting http server on port 6161
CORRUPTION WARNING in SBCL pid 206086 tid 206091:
Memory fault at 0x7f9c7c58b000 (pc=0x53617132 [code 0x53616f20+0x212 ID 0x43a3], fp=0x7f696af2dbc0, sp=0x7f696af2db68) tid 206091
The integrity of this image is possibly compromised.
Continuing with fingers crossed.
CORRUPTION WARNING in SBCL pid 206086 tid 206091:
Memory fault at 0x7f9c7c58b000 (pc=0x53617c03 [code 0x53617a30+0x1D3 ID 0x43a5], fp=0x7f696af2dc40, sp=0x7f696af2dc18) tid 206091
The integrity of this image is possibly compromised.
Continuing with fingers crossed.
Would some one please help me look into what is going on here? It just does not make sense the same codes work well in a REPL or run as a script, but do not work as an executable. Is there something wrong with how I generate the executable?
My OS is LinuxMint 21. sbcl version is 2.2.8, hunchentoot version is 1.3.0.
Many Thanks!
SOME UPDATES This issue can be easily reproduced with the latest SBCL 2.2.9 + latest hunchentoot 1.3.0. With a well prepared environment, just run the script and generate the executable file, and you are ready for the investigating. Since both SBCL and hunchentoot are very popular in the community, it just does not make sense we don't have an explanation of this problem.
ANOTHER UPDATE I change the method of generating the executable, and it WORKS this time. It turns out that I have to create the executable from a REPL, rather than use the script file above. I think it might relate to the shebang line, the "--script" will disable the ldb debugger, it is probably not an ideal way to generate executable. The lesson has been learned.
FINAL UPDATE Actually we still can generate the executable from a script file, as long as we don't use the "--script" option. For example, put these lines at the beginning of the script file, and it works (Remember remove the last two lines from the original script):
#|
# This is the correct way to generate the executable from this script file
sbcl --noinform --no-userinit --load "$0" --eval $'(sb-ext:save-lisp-and-die "http-server" :toplevel \'http-server::main :executable t)'
exit 0
|#
You could use Roswell.
Install Roswell following:
https://towardsdatascience.com/how-to-set-up-common-lisp-ide-in-2021-5be70d88975b
(I am the author of this article).
Generate a folder service and cd service into it.
I put your script into the file: service.lisp
(ql:quickload :hunchentoot)
(defpackage :http-server
(:use :cl :hunchentoot))
(in-package :http-server)
(defvar *my-acceptor* (make-instance 'easy-acceptor :port 6161))
(defun main ()
(format t "Starting http server on port ~a~%" (acceptor-port *my-acceptor*))
(start *my-acceptor*)
(handler-case
(loop do (sleep 1000))
(condition () nil)))
(defun hello ()
(format nil "Hello, it works!"))
(push
(create-prefix-dispatcher "/hello.html" #'hello)
*dispatch-table*)
;; (sb-ext:save-lisp-and-die "http-server" :toplevel 'main :executable t)
(main)
Then, I run
$ ros init service
Which generates a file service.ros Which content I let be:
#!/bin/sh
#|-*- mode:lisp -*-|#
#|
exec ros -Q -- $0 "$#"
|#
(progn ;;init forms
(ros:ensure-asdf)
#+quicklisp(ql:quickload '() :silent t)
)
(defpackage :ros.script.service.3874727090
(:use :cl))
(in-package :ros.script.service.3874727090)
(defun main (&rest argv)
(declare (ignorable argv))
(load "service.lisp")
(main))
;;; vim: set ft=lisp lisp:
Then, you have to install the script into roswell:
$ ros install service.ros
It will show a path. In my case sth like: ~/.roswell/bin/service.
There is a linux program called service already.
So I alias this: $ alias serveit="~/.roswell/bin/service"
Now I can fire: $ serveit
serveit
To load "hunchentoot":
Load 1 ASDF system:
hunchentoot
; Loading "hunchentoot"
....
Starting http server on port 6161
Roswell scripting is explained here:
https://roswell.github.io/Roswell-as-a-Scripting-Environment.html

Common Lisp Executable doesn't do anything

I have followed all the steps in the cl-cookbook. I created a webapp project with quickprojects.
I have my .asd file:
(asdf:defsystem #:serve
:description "Describe server here"
:author "Your Name <your.name#example.com>"
:license "Specify license here"
:version "0.0.1"
:serial t
:depends-on (#:hunchentoot)
:components ((:file "package")
(:file "serve"))
:build-operation "program-op" ;; leave as is
:build-pathname "serve"
:entry-point "serve:main")
I have the lisp server file:
(ql:quickload "serve")
(in-package #:serve)
(defvar *acceptor* (make-instance 'hunchentoot:easy-acceptor :port 4242
:document-root #p"www/"))
;; start the server
(defun main ()
(hunchentoot:start *acceptor*))
(setf (hunchentoot:acceptor-document-root *acceptor*) #p"./www/")
I have the package.lisp file:
(defpackage #:serve
(:use #:cl)
(:export main))
Finally, I have the make file for creating the executable:
build:
sbcl \
--eval '(load "serve.asd")' \
--eval '(ql:quickload "serve")' \
--eval "(asdf:make :serve)" \
--eval '(quit)'
When the executable comes out after running make build, and I run it with ./serve.... nothing happens.
My expectation is that the server will run as it does when i run it with emacs.
My goal is to send the executable to the server to run it. Not sure if that is the best deploy process. But at the moment, it's good enough for testing.
Even more worrying is that when I send the executable to my ubuntu server, i get a zsh error. This only happens when I build it on my MacOs and send it to ubuntu. However, when I build on ubuntu (i rebuilt the project on the VM to test it), the executable does nothing.
Your main problem is that your main function immediately returns, terminating the server as soon as it is started. I would change it as follows:
;; start the server
(defun main ()
(hunchentoot:start *acceptor*)
(sb-impl::toplevel-init))
When you rebuild and run ./serve, a simple prompt appears *, which is the SBCL REPL. Your webserver is running in another thread. This can be useful to query the state of the server, or debug. You can even start a Swank server to connect and hack the code while it runs.
When you want to stop the server, press CTRL-D to exit the REPL and the program terminates.
You can imagine other mechanisms to keep the server running until everything stops (like joining all threads, etc.) but this should be enough for testing.
Also,
(ql:quickload "serve")
This is not required in serve.lisp, the code by itself should not contain invocations to ql:quickload, it is sufficient to do it in the build command.
Likewise:
--eval '(load "serve.asd")' \
can be removed if you put your .asd file in a place where quicklisp can find it, see 4.1 Configuring ASDF to find your systems.

Calling ssh with system in R shell eats subsequent commands

My workflow is to send commands from an emacs buffer to an R session in emacs via the ESS package.
a=0;
system("ssh remotehost ls")
a = a+1;
When I run the three lines above in rapid succession (i.e. submit them to the R buffer), the value of a at the end is 0. When I run them slowly, a is 1.
I've only had this issue running an ssh command via system. In all other cases, the commands queue up and all run sequentially.
My colleagues have the exact same issue with their R/vim setup. But we don't have the same issue in RStudio.
Any suggestions here would be great .
ssh eats up any stdin during the system() command. If you paste it line by line then ssh terminates before you submit a=a+1 and thus it gets passed to R instead of ssh. Use system("ssh .. < /dev/null") or system(..., input="") if you don't want terminal input to be eaten by the subprocess.

How can I launch an x-window from emacs ess when running R on a server?

I am using emacs-snapshot with the ssh.el package, following the instructions from the ess manual.
There are a few ways to open an R session, but this is how I do it:
open emacs
C-x C-f /server:dir/file.R this puts me in ESS [S] mode
Type 'plot(1)'
C-c C-n to run
emacs asks for starting directory, and I choose the /server:dir/
I would like for a figure to pop up but it wont.
This also doesn't work when using ess-remote in shell or tramp mode, but it does work if I set the starting directory to my local desktop.
Any advice much appreciated. My current workaround is to print the file to pdf and then open pdf in DocView mode, but this takes a few extra steps and is slow.
I do it the other way around:
ssh -X some.server.com to connect to a remote server with x11 forwarding.
emacsclient -nw to restart an Emacs session that is already running
plot(cumsum(rnorm(100))) in R as usual
Then the plot windows appears on the initial machine I ssh'ed away from.
Edit: As a follow-up to the comment: This works for any emacs, either emacs or emacs-snapshot. For a long time I used (server-start) in the ~/.emacs but now I prefer that (just once) lauch emacs --daemon after which I can then connect to via emacsclient (which also exists as emacsclient-snapshot). I really like this -- it gives me Emacs around R in a persistent session that I connect, disconnect and reconnect to.
I selected Dirk's answer because he pointed me in the right direction, and especially for lowering the energy of activation required to visualize my data, but here I am going to give the details of how I got this to work on my desktop.
1) set ssh keypairs (I had previously done this, full instructions for Ubuntu here)
mkdir ~/.ssh
chmod 700 ~/.ssh
ssh-keygen -t rsa
ssh-copy-id username#hostname
2) include the following in ~/.ssh/config
Host any_server_nickname
HostName hostname
User username
ForwardX11 yes
3) open emacs on local machine
4) C-x C-f
5) /any_server_nickname:dir/file.R for files in home directory or /any_server_nickname:/path/to/file.R
6) plot(1)
7) C-x C-b to evaluate entire buffer.

Open an Emacs buffer when a command tries to open an editor in shell-mode

I like to use Emacs' shell mode, but it has a few deficiencies. One of those is that it's not smart enough to open a new buffer when a shell command tries to invoke an editor. For example with the environment variable VISUAL set to vim I get the following from svn propedit:
$ svn propedit svn:externals .
"svn-prop.tmp" 2L, 149C[1;1H
~ [4;1H~ [5;1H~ [6;1H~ [7;1H~
...
(It may be hard to tell from the representation, but it's a horrible, ugly mess.)
With VISUAL set to "emacs -nw", I get
$ svn propedit svn:externals .
emacs: Terminal type "dumb" is not powerful enough to run Emacs.
It lacks the ability to position the cursor.
If that is not the actual type of terminal you have,
use the Bourne shell command `TERM=... export TERM' (C-shell:
`setenv TERM ...') to specify the correct type. It may be necessary
to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.svn: system('emacs -nw svn-prop.tmp') returned 256
(It works with VISUAL set to just emacs, but only from inside an Emacs X window, not inside a terminal session.)
Is there a way to get shell mode to do the right thing here and open up a new buffer on behalf of the command line process?
You can attach to an Emacs session through emacsclient. First, start the emacs server with
M-x server-start
or add (server-start) to your .emacs. Then,
export VISUAL=emacsclient
Edit away.
Note:
The versions of emacs and emacsclient must agree. If you have multiple versions of Emacs installed, make sure you invoke the version of emacsclient corresponding to the version of Emacs running the server.
If you start the server in multiple Emacs processes/frames (e.g., because (server-start) is in your .emacs), the buffer will be created in the last frame to start the server.
There's emacsclient, gnuserv, and in Emacs 23, multi-tty that are all useful for this. Actually I think in Emacs 23, emacsclient has all of the interesting functionality of gnuserv.
Not entirely true. ansi-term can run an emacs fine (although I usually run mg for commit logs, in the rare event I don't commit from emacs directly). eshell can also run an emacs if you start a screen first and run it from within there.
Along with using emacs client/server, I am using this script to invoke emacs.
This will start emacs if it is not running yet, or just open a new emacs buffer in the running emacs (using gnuclient). It runs in the background by default, but can be run in the foreground for processes that expect some input. For example, I am using this as my source control editor, when entering a change list description. I have "SVN_EDITOR=emacs sync", so I can do "svn commit" in an emacs shell, and it will open the svn editor in a new emacs buffer in the same emacs. When I close the buffer, "svn commit" continues. Pretty useful.
#!/bin/sh
if [ -z $EMACS_CMD ]; then
EMACS_CMD="/usr/bin/emacs"
fi
if [ -z $GNUCLIENT_CMD ]; then
GNUCLIENT_CMD="/usr/bin/gnuclient"
fi
if [ "$1" = "sync" ]; then
shift 1
sync=true
else
sync=false
fi
cmd="${EMACS_CMD} $*"
lsof $EMACS_CMD | grep $USER >/dev/null 2>&1
if [ "$?" -ne "1" ]; then
cmd="${GNUCLIENT_CMD} $*"
fi
if [ $sync = "true" ]; then
$cmd
else
$cmd &
fi
I wanted to do something similar for merging in an emacs shell via mercurial. Thanks to the posters here, i found the way. two steps:
add: (start-server) in your .emacs file (remember to load-file after your change)
in your hgrc:
[merge-tools]
emacs.executable = emacsclient
emacs.premerge = False
emacs.args = --eval "(ediff-merge-with-ancestor \"$local\" \"$other\" \"$base\" nil \"$output\")"
When I have (start-server) in my .emacs I get this error....
Debugger entered--Lisp error: (void-function start-server)
(start-server)
eval-buffer(#<buffer *load*> nil "/Users/jarrold/.emacs" nil t) ; Reading at buffer position 22768
load-with-code-conversion("/Users/jarrold/.emacs" "/Users/jarrold/.emacs" t t)
load("~/.emacs" t t)
#[nil "^H\205\276^# \306=\203^Q^#\307^H\310Q\202A^# \311=\2033^#\312\307\313\314#\203#^#\315\202A^#\312\307\$
command-line()
normal-top-level()
....I am using GNU Emacs 22.1.1
And this is the version of Mac OS-X I am using:
shandemo 511 $ uname -a Darwin Facilitys-MacBook-Pro.local 10.8.0
Darwin Kernel Version 10.8.0: Tue Jun 7 16:33:36 PDT 2011;
root:xnu-1504.15.3~1/RELEASE_I386 i386
Note that m-x ansi-term appears to allow me to successfully hg commit inside of its shell. However, that shell does not let me scroll through the buffer with e.g. c-p or c-n so I would prefer to us m-x shell.

Resources