Hi, The ability to tangle to multiple destinations is a very convenient way to manage cluster configurations. No, it's more than that: it's an *awesome* way to deploy and keep clusters configs and repros well organized.
The following *org-babel-n-tangle*, is just a small derivation of *org-babel-tangle*. It's displayed here as a diff not with the intent to be applied as a patch, but to show the very little differences required in order to get this working. #+begin_src diff diff -u ~/.emacs.d/repos/org/lisp/ob-tangle.el ~/tmp/ob-ntangle.el --- ~/.emacs.d/repos/org/lisp/ob-tangle.el +++ ~/tmp/ob-ntangle.el @@ -238,8 +238,12 @@ (org-babel-tangle-file filename))) ;;;###autoload -(defun org-babel-tangle (&optional arg target-file lang-re) - "Write code blocks to source-specific files. +(defun org-babel-n-tangle (&optional arg target-file lang-re) + "Write code blocks to source-specific files +located into the directories designated by the :n-tangle parameter +then onto subsequent directory and file of the :tangle parameter. +Performs like `org-babel-tangle' adding an extra iteration over +a list of directories, potentially different hosts and protocols Extract the bodies of all source code blocks from the current file into their own source-specific files. Return the list of files. With one universal prefix argument, only tangle the block at point. @@ -268,12 +272,19 @@ (tangle-file (when (equal arg '(16)) (or (cdr (assq :tangle (nth 2 (org-babel-get-src-block-info 'no-eval)))) - (user-error "Point is not in a source code block")))) + (user-error "Point is not in a source code block")))) + (targets (or (cadr (assoc (cdr + (assoc :n-tangle (nth 2 (org-babel-get-src-block-info)))) + org-babel-ntangle-destinations)) + '(nil))) ; iterate on one local target path-collector (source-file buffer-file-name)) + + (dolist (target targets) ;; iterate the n-tangle group + (progn (mapc ;; map over file-names (lambda (by-fn) - (let ((file-name (car by-fn))) + (let ((file-name (concat target (car by-fn)))) (when file-name (let ((lspecs (cdr by-fn)) (fnd (file-name-directory file-name)) @@ -354,6 +365,7 @@ (if (equal arg '(4)) (org-babel-tangle-single-block 1 t) (org-babel-tangle-collect-blocks lang-re tangle-file))) + )) (message "Tangled %d code block%s from %s" block-counter (if (= block-counter 1) "" "s") (file-name-nondirectory #+end_src In order to use this *:n-tangle* parameter, the destinations are declared in groups of host and/or root folders. #+begin_src elisp (setq org-babel-ntangle-destinations '(("test-1" ("/tmp/test/host-A" "/tmp/test/host-B" )) ("hosts-A&B/tmp" ("/-:hostA:/tmp/" "/-:hostB:/tmp/")))) #+end_src Calling *org-babel-n-tangle* with the universal argument runs the tangle processor, not on the entire file, but for the current block. The tangled output goes into the designated group. #+begin_example #+begin_src elisp :n-tangle "hosts-A&B/tmp" :tangle /x/y :mkdirp t (org-babel-n-tangle '(4)) #+end_src #+end_example In the above example the tangled outputs goes to *hostA:/tmp/x/y* and *hostB:/tmp/x/y* using a default protocol. In the absence of *:n-tangle* or when *org-babel-ntangle-destinations* is nil. *org-babel-n-tangle* behaves like *org-babel-tangle* What do you think ? Phil /"Oh what a tangled web we weave..."/