emacs to automatically rsync? - emacs

This was discussed in a emacs StackExchange Discussion where Howard Abrams and gavinb mentioned something that could work. However, I am such a newbie to emacs, and not a programmer at all, that I have no idea of how to get his code to work in my emacs editor. I have started to use org-mode and have used the "easy customization" mode to change things in "[-]-\ Group Org", but I don't know enough to know what to do with it to implement a complete solution.
I assume that the gist code of Mr. Abrams works to run one script named ".on-save" that lives in the same directory as the file that is being saved. And that this code runs the .on-save script and passes the saved file's name to that script to process. At that point I get lost in how to get a rsync script to process the saved file's name.
Would I put the code that Mr. Abrams mentions in my ~.emacs file?
Alternatively do I use "easy customization" to run Mr. Abrams code?
If I managed to run/install the code, how would my rsync script look to make use of his code to pass the file name of the file being saved to the rsync script for processing.
Thanks.
Aaron

So I bound Alt-F11 to trigger a shell script ".rsync-org-mode.sh".
In my .emacs file I put the following:
(defvar script-name "~/.rsync-org-mode.sh")
(defun call-my-script-with-word ()
(interactive)
(shell-command
(concat script-name
" "
(thing-at-point 'word))))
(global-set-key (kbd "M-<f11>") 'call-my-script-with-word)
The shell script:
#!/bin/bash
rsync -avh --delete ~/My-Org-Directory/ /My-Backup-Org-Directory/
I saved the script as ~/.rsync-org-mode.sh and made it executable with chmod+ It rsync's my entire org-mode directory.
To use it I periodically save to backup using Alt-F11. I did not want it to be automatic for fear that it would automatically sync a bad copy.
Very very low tech, but it is adequate for my needs, and it will sync the directories. Lawlist's solution in the post he referenced is great, and more comprehensive, but since I fuse mount my only sftp directory prior to each emacs session, it was more than I really needed.

Related

start emacsclient within emacs (like magit does)

I am looking for ways to start emacs within shell-mode, and I want the client to connect to the enclosing emacs instance so I don't need to switch to the instance running the server to edit the file.
I sense it is doable because magit is already doing something like this: the commit message is edited by emacsclient, and always opened in the enclosing instance. I don't even need to start the server explicitly!
My primary usage is to do git commit from shell-mode. I can't rely on magit because I have to use some customized git version with special command. Anyway I think it would be cool thing to do.
UPDATE:
I found the magit function magit-with-emacsclient that does the trick here:
https://github.com/magit/magit/blob/master/magit.el#L1979
Any help to turn the function into a shell script that can act as the default editor of git will be greatly appreciated! I will also try and post the code if I can make it work.
UPDATE 2:
Here is my solution. It requires start the server beforehand with pid in the socket name and then set your $EDITOR to be emacsclient connecting to that server.
Put this in your init.el
; start a server with a pid
(require 'server)
(defun server-start-pid ()
(interactive)
(when (server-running-p server-name)
(setq server-name (format "server%s" (emacs-pid)))
(when (server-running-p server-name)
(server-force-delete server-name)))
(server-start))
and run server-start-pid before you launch the editor in your shell-mode.
put this script emacsclient-pid in your PATH. It recursively find the parent process until it finds the emacs instance and invoke emacsclient on the right socket:
#! /usr/bin/python
import os, sys
import psutil
def get_pid(name):
pid = os.getppid()
while True:
proc = psutil.Process(pid)
if name in proc.name():
break
pid = proc.ppid()
return pid
if __name__ == '__main__':
pid = get_pid("emacs")
# pass the argument to emacsclient
args = ' '.join(sys.argv[1:])
cmd = "emacsclient -s server{pid} {args}".format(**globals())
print cmd
os.system(cmd)
And put this in your .bashrc
if [[ $EMACS"x" == tx || $TERM"x" == dumbx ]]; then
export PAGER=/bin/cat
export EDITOR='emacsclient-pid'
else
export PAGER=/usr/bin/less
export EDITOR='emacs -q -nw'
fi
I have split the code responsible for client-server interaction into a separate library with-editor. It's part of git-modes' next branch. Magit will start using that once I merge its next branch into master. You should study that instead of the old implementation in magit itself, because it puts all things related to this in one place and because it is also improved in many ways. E.g. it also works when using tramp.
with-editors can be used by other packages besides magit. That's one of the reasons why I have split it into a separate library/package. But I have not yet implemented the parts not actually needed by magit. E.g. the functionality it provides could also be used with shell-command, see https://github.com/magit/git-modes/pull/96.
Something similar would probably work for shell-mode too. From a very quick look I think the function that would need to be advices in this case is comint-exec. I will probably not work on this soon, but eventually I will get back to this. Meanwhile have a look at that library yourself. Understanding what it does won't be easy without good knowledge of elisp and how emacs handles child processes, though. The only advice I can give you here is to also read the issues that concern with-editor in the magit/git-modes repository on github.
Ps. Translating this to a shell script won't work, because certain things have to happen in Emacs before the child process is started, like starting the server.

What is the best way to open remote files with emacs and ssh

I connect to the remote machine with ssh user#192.168.1.5. When I need to open a file in the remote machine I do, e.g.,
emacs /usr/share/nginx/html/index.html
and that opens the index.html file in the shell. I noticed that some emacs commands work but others do not work. For instance, C-w does not work; M-< does not work. How can I fix this, and what is the best way to work with emacs and ssh?
I found this question but it made me more confused.
I generally prefer opening remote files from a local Emacs instance.
While running Emacs on your local machine, opening a remote file over ssh is not much different than opening any other file besides a slightly different syntax.
For ssh, you can type C-x C-f. Now, in the minubuffer you want to type /ssh:user#host:/path/to/file (Note that tab completion will work once you start typing a path. Also note the leading / character). See the full docs here.
In your example, that would be:
C-x C-f /ssh:user#192.168.1.5:/usr/share/nginx/html/index.html
Now you can edit remote files over ssh in Emacs while using your local configuration and any installed packages, etc...
Just to add to the answer above, you can write shortcuts for machines that you use
frequently:
(defun connect-remote ()
(interactive)
(dired "/user#192.168.1.5:/"))
This will open a dired buffer on a remote machine. You can navigate this buffer
as you would a local one.
If you have set up ssh keys for the remote machine, you don't even have to enter the password.
If you have a bunch of remote machines, you can give some recognizable name
to each function, e.g. connect-cupcake, connect-kitkat and use smex package for completion.
And to add to #abo-abo's post about "shortcuts" --
Use Emacs bookmarks. Just create bookmarks normally, when you visit a remote file or directory. Then just use C-x r b to jump to a remote bookmark, whose name you provide (with completion).
If you use Bookmark+ then remote bookmarks are highlighted specially in the *Bookmark List*, so you can recognize them more easily. And remote bookmarks that must be accessed by su or sudo (root) are highlighted differently.
If you use Dired+ then you can also quickly bookmark multiple remote files or directories, by visiting their containing remote directory in Dired, marking them, and hitting C-x b. No need to give the bookmarks names; they are named after the files. Even if you never use those bookmarks for navigating to the remote files, you can use them with Bookmark+ tags to organize the files and thus operate on subsets of them.
If you use Icicles then whenever you use a command to jump to a bookmark, you can narrow the completion candidates to those that are remote by hitting C-M-# during completion.
The original poster expressed interest in opening remote files as the root user. This can be done with the command:
C-x C-f /ssh:you#remotehost|sudo:remotehost:/path/to/file RET
More documentation can be found here: https://www.emacswiki.org/emacs/TrampMode#toc14
A Simple Answer that focuses on the remote machine:
If I plan to do all my emacs work on the remote machine, I use
ssh -X username#hostname
and then run emacs in the remote session, displaying back on my local machine. It's an old question but I wanted to throw this in for completeness. Granted there are some xhost / X config issues but in many networks this will work right off the bat!
SSH mode for emacs is what you're looking for.
Once you have it set up you just run
M-x ssh RET hostname RET
Then it prompts you for your password twice (once for the command line, once for loading files).
For the most part you can treat it like any other shell (non-interactive and a few minor differences, but that's it).
It keeps track of which directory you're in, so when you want to open a file from the directory you're looking at it automatically starts in the right directory and you just need to enter in the file name.
Emacs Wiki has more info too.

SLIME on Windows 7

I'm trying to get set up with SLIME on a Windows 7 box, but running M-x slime gives me the error
Spawning child process: invalid argument
I have inferior-lisp-program set to "C:\\Program Files\\ccl\\wx86cl.exe" (which is factually correct, and running (comint-run inferior-lisp-program) gives me a working CCL prompt), and the slime directory added to my 'load-path.
What am I doing wrong?
EDIT: Tried loading up the same environment through the Windows edition of lispbox, and it runs SLIME fine. I'd prefer not to use that one because it packages an older Emacs, CCL and SLIME than I want.
The message you received means that there's a high chance that there was a syntax problem with the command given to shell. This would be caused by having characters in the file name, which can be interpreted as doing something special. So, it looks like Emacs was trying to call C:\\Program "program" with an argument Files\\ccl\\wx86cl.exe.
There are several ways to address the error:
There has to be an escaping function, something like:
(shell-quote-argument "C:\\Program Files\\ccl\\wx86cl.exe")
But since you cannot affect how the file name is passed to the function which creates the process, this isn't going to work.
You can move the program you want to call to a directory with "safe" name.
You can move the executable to be on the system path (%PATH% variable in Windows) - through changing environment variables and appending the directory with the executable to it.
One more option is to add the directory with the executable to exec-path variable in Emacs. This variable holds a list of all directories looked up for programs to run, if you just call a program by name, rather then by full path. This also (at least for me) makes my .emacs file easier to port between different systems.

Running emacs from the command line and handling locked files

I'm using org-mode and am looking to export my agenda (example of an agenda) to a text file so that I can display it with conky. The org-mode manual features this command line example to do this:
emacs -batch -l ~/.emacs -eval '(org-batch-agenda "t")' | lpr
I've modified this like so:
emacs -batch -l ~/.emacs -eval '(org-batch-agenda "e")' \
> ~/org/aux/agenda-export.txt
I have this set as a cron job to run every 5 minutes. It works great unless I actually have emacs open. Then I noticed that the file agenda-export.txt was empty. In running this manually from the coammand line vs. through cron, I get this error (or similar depending on the files I have open):
...~/org/file.org locked by jwhendy (pid 10935): (s, q, p, ?)?
I was going to write a script to perhaps export to agenda-export-test.txt, then perhaps check for an empty file or no lines (wc -l == 0 maybe?). If true, leave the existing file alone and delete agenda-export-test.txt. If not, then move agenda-export-test.txt to agenda-export.txt.
But... when I try to run such a script, I'm met with the same emacs inquiry about whether to steal the lock, proceed, or quit. I'm fine with proceeding, as I don't think org-agenda does anything to the files and thus it wouldn't harm anything... but I don't know how to tell emacs to "force" or choose "proceed" if problems are encountered. I need something non-interactive.
So, to summarize, my thoughts were to try:
passing a --force option or similar to emacs to make it proceed at the pause
see if the exported tmp file has any lines and deal with it accordingly
tell emacs to run in "read only mode" (but I don't think it exists)
The main issue is that with cron, I'm not there to tell the process what to do, and so it just just make an empty file as the exported results. How can I handle this locked file business with a "blind" process like cron that can't respond?
I've tried asking the mailing list as well without a working outcome. [1] I wondered if someone here might have ideas.
[1] http://www.mail-archive.com/emacs-orgmode#gnu.org/msg45056.html
Have you tried copying file without using emacs?
put in your crontab:
cp ~/org/file.org /tmp/export.org && emacs -batch .... /tmp/export.org ..
A regular "cp" command should not copy emacs locks. Of course, once in a while you might get a damaged file if you save agenda just during cp command, but this should not be too bad.

How to gracefully shutdown emacs daemon? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 6 years ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
Improve this question
On login to Ubuntu, I start an Emacs (version 23) daemon using Ubuntu's Startup programs. I then start Emacs clients whenever I need to edit something. When I logoff from Ubuntu, it says Emacs is still running, of course. I need to attach a script somewhere to tell Gnome to shutdown emacs when I logoff/shutdown.
1) What should the script look like? "kill-emacs" doesn't seem to work.
2) Where should I put this script? There's nothing in the startup programs (System->Sessions menu) panel that looks useful. I'd prefer something that works in the user's account, rather than hacking the PostSession script or something else with root access.
ShreevatsaR is right, the answer is kill-emacs or save-buffers-kill-emacs, both of which are interactive, and so can be run from within Emacs with M-x save-buffers-kill-emacs. This is probably the best way to do it, since you will get to save modified files.
Another alternative is to make a shell file like this:
#!/bin/bash
emacsclient -e "(kill-emacs)"
Which you can run from wherever you like (menu icon, panel, etc).
This linuxquestions.org page has a Python script that can be run during login that listens for the 'save yourself' event that Gnome emits during shutdown. You could modify that to do the:
emacsclient -e '(save-buffers-kill-emacs)'
Official docs: https://www.emacswiki.org/emacs/EmacsAsDaemon#toc8
Another addendum to ShreevatsaR: the python script works like a charm, but I'd suggest using
emacsclient -e '(let ((last-nonmenu-event nil))(save-buffers-kill-emacs))'
as command. Setting last-nonmenu-event to nil forces emacs into mouse-mode, so you get "nice" dialog boxes instead of prompts in the minibuffer.
Or even more fancy (somewhere in your emacs config):
(defun shutdown-emacs-server () (interactive)
(when (not (eq window-system 'x))
(message "Initializing x windows system.")
(x-initialize-window-system)
(when (not x-display-name) (setq x-display-name (getenv "DISPLAY")))
(select-frame (make-frame-on-display display '((window-system . x))))
)
(let ((last-nonmenu-event nil)(window-system "x"))(save-buffers-kill-emacs)))
and then:
emacsclient -e '(shutdown-emacs-server)'
If you use systemd you may be interested in this unit file that lets you manage an Emacs server gracefully from within your console/remote system:
[Unit]
Description=Emacs: the extensible, self-documenting text editor
[Service]
Type=forking
ExecStart=/usr/bin/emacs --daemon
ExecStop=/usr/bin/emacsclient --eval "(kill-emacs)"
Restart=always
# Remove the limit in startup timeout, since emacs
# cloning and building all packages can take time
TimeoutStartSec=0
[Install]
WantedBy=default.target
(it kills the daemon in the same way folks already suggested above.)
You could put and name the unit file like ~/.config/systemd/user/emacs.service so it's bind to your user instead running it as root; to manage it:
$ systemctl --user {enable,disable,start,restart,stop} emacs.service
Please note: I took this note from somewhere else, can't remember where though.
I think that using a script in /etc/init.d is a cleaner solution.
Check here for more details
http://www.emacswiki.org/emacs/EmacsAsDaemon
the answer from willert contains a small bug. it must look like
(defun shutdown-emacs-server () (interactive)
(when (not (eq window-system 'x))
(message "Initializing x windows system.")
(x-initialize-window-system)
(when (not x-display-name) (setq x-display-name (getenv "DISPLAY")))
(select-frame (make-frame-on-display x-display-name '((window-system . x))))
)
(let ((last-nonmenu-event nil)(window-system "x"))(save-buffers-kill-emacs)))
you can put emacsclient -e "(kill-emacs)" in GDM's PostSession directory or directly in the Default script:
/etc/gdm/PostSession/Default
see also GDM documentation.
Perhaps the most general solution would be to put a script in the system PostSession directory that runs every executable script in ~/.logout-d, or something similar. Then you can put whatever scripts you like in ~/.logout-d, and they will be run on logout.
The script might be as simple as run-parts ~/.logout.d.
Note: Untested, though I do use a startup script that does run-parts ~/.autostart.d, and that's been working fine forever.
Edit: Of course, it would be just as easy to modify the above python script to execute that same command, but I personally don't like the idea of loading a script for my entire session just to run commands on logout.
Just open some terminal and pkill -TERM emacs