0

I've defined a custom command with shell-interpreter to rsync files to my VPS...

(defun rsync_html ()
  (interactive)
  (with-shell-interpreter
   :path "~/org"
   :interpreter "bash"
   :form
   (message "rsync org html output to OVH")
   (message (shell-command-to-string "rsync -av ~/org/*.html ovh:~/www/. --exclude='*.org'"))))

It works, I can run M-x rsync_html and the files are get copied over. What I'd now like to do though is have a hook that runs after compiling .org files to HTML that runs this command.

I've looked through Documentation for Org hooks, commands and options and found the org-html-export-as-html which I am guessing is the command run on export. So I've written...

(add-hook 'org-html-export-as-html 'rsync_html)

...but it doesn't seem to work. Before reaching this point I had already tried (add-hook 'org-babel-after-execute-hook 'rsync_html) but this tried syncing after processing every chunk which whilst it achieved the desired result because it ran after the last chunk had processed is wasteful/inefficient (particularly if the SSH key isn't loaded into the keyring).

I'm unsure how to go about investigating why the hook isn't picked up, perhaps I've chosen the wrong command to hang my hook on but I think its right (if not I'm stumped as to how to see what it should be).

Advice and pointers welcome.

Thanks.

1

There is no such hook, but you can write a function that does what you want and execute that instead:

(defun ndk/org-export-to-html-and-rsync ()
   (interactive)
   (org-export-as 'html)
   (rsync-html))

You can even bind to a key so that you can execute it easily:

(define-key org-mode-map (kbd "C-c z") #'ndk/org-export-to-html-and-rsync)

Notes:

  • Hooks are usually added to a function in the middle of the code: that way, they allow you to influence the way the function operates without having to rewrite it. That mitigates the need to write many functions, mostly identical except for one little detail in the middle. So they are a way to customize the behavior of a function.

  • Another way to customize a function is through the advice mechanism: that allows you to run something before, or after, or around a given function, but preserve the name (and e.g. any keybindings that call that function). You could use that here, but it is simpler to just define a new function that composes the two functions that you want to run.

  • A more general mechanism to do the export and then e.g. send the results to a web server, is the Publishing mechanism that Org mode provides. If your setup becomes more complicated in the future, you might want to investigate that mechanism.

  • Instead of running shell commands to rsync things to a remote machine, you can use Remote Files through the Tramp mechanism that Emacs provides. The Org mode publishing link above contains examples of that usage.

  • The usual convention of naming things in Emacs Lisp uses dashes, rather than underscores: rsync-html rather than rsync_html.

Finally, even though they are not needed in this case, here's how I go about finding hooks when I need them. The method depends on the convention that hook variables are named <mumble>-hook (there are exceptions, mostly for historical reasons, but almost all modern code adheres to that convention). The other important convention is that packages use a prefix for all their interfaces (functions and global variables); e.g. Org mode uses the prefix org-.

Emacs is self-documenting: you can ask it to give you a lot of information, so you don't need to chase down manuals (at least at first; when you are ready to dig deeper, of course the manuals are indispensable). As an example, let's discover some hooks (N.B. Hooks are variables: a hook variable has a value which is a list of functions - or nil which is the empty list; when a function runs the hook, all the functions in the list are evaluated, one after the other.)

We can ask Emacs for information about any variable, but in this case we want to ask about a hook variable: C-h v org-mode-hook RET - that gives us the doc string of the org-mode-hook variable.

If I'm looking for a hook but I don't know its name (or if it even exists), then I can use the documentation facility of Emacs in conjunction with another facility that Emacs provides: completion. If I say C-h v org--hook TAB then I get a completion buffer containing a list of all the variables that have names of the form org-<mumble>-hook: I use this all the time to get the list, eyeball it for candidates and then zero in on the most likely ones: select one to see its doc string. Lather, rinse, repeat for any others in the list.

I can be more selective to begin with: C-h v org-export--hook will give me all the hooks of the form org-export-<muble>-hook; the results here are paltry: just three hooks (that look unpromising for what you wanted to do): org-export-before-parsing-hook org-export-before-processing-hook org-export-stack-mode-hook so let's see if there are any HTML-related ones: C-h v org-html--hook TAB - no results on that one, so it doesn't look as if there's a hook to do what you want. As noted, the fact that there is no such hook is no limitation in this case: hooks are for a different purpose. But I hope that the method of discovering hooks will be useful to you in the future.

For completeness, here are a few more of the "self-documenting" capabilities of Emacs: you can use C-h f <function-name> RET to get the doc string of a function, but also to find functions using completion the same way. And do C-h ? to get help on help: what else you can type after C-h to ask Emacs for useful information.

2
  • Thanks for the comprehensive answer. Why a hook? Because I thought it was a way to achieve what I wanted without writing a function. I use git post-commit hooks (although commits are not necessarily the end of git workflow). Also wanted to avoid another key sequence by writing a function. Thanks also for the explanation of the self-documenting help system I had also used that to search, just didn't write so and felt it useful to include a link to the documentation. Hadn't heard of the Publishing so will read up on that. Ta.
    – slackline
    Dec 21 '20 at 8:23
  • You can write it as an after advice: that would keep the name of the old function (and its keybindings); but I would not recommend it. The "bare" function is much too useful and advising it like this would specialize it so much that it would make it useless in the general case. You can arrange to add the advice, then use the advised function and then remove the advice, but I think that's more of a pain than adding the function with an extra keybinding.
    – NickD
    Dec 21 '20 at 13:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.