* [2024-07-12 13:23] Ihor Radchenko:> Phil <p...@7d.nz> writes:
To tangle to multiple destinations

a logic extension of the existing tangle mechanism.
1) Introduce :tangle-directory parameter that defines
   relative directory to be used as tangle target; this
   directory, if defined, will be used instead of the Org
   file directory to expand the tangle target;
2) Allow :tangle-directory and :tangle-file to be a list
   of targets to write.

Then, we can modify `org-babel-effective-tangled-filename'
to account for :tangle directory and modify
`org-babel-tangle' (as you did) to write to multiple
targets.

All right. So I have it working for single blocks by
modifying only `org-babel-tangle' with :tangle-directory
accepting a single string or a list, e.g.

:tangle-directory '("dir1" "/ssh:host1:/dir2" "/-::/etc")

The option is ignored for file-wide tangle.

What do you think of, instead of adding :tangle-directory,
modifying :tangle to make it accept also a list?

Since I may not get back to this in the next weeks,
I'm saving the following note and a patch as a current
status of the function for later.

=:tangle-directory dir= is set
- Tangle globally
      |--------+------------------+--------------|
      | tangle | expected result  | current      |
      |--------+------------------+--------------|
      | yes    |             ignore dir          |
      | no     |             ignore dir          |
      | file   | block → dir/file?| block → file |
      |--------+------------------+--------------|
- Tangle a single block
      |--------+------------------+---------------------------|
      | tangle | expected result  | current                   |
      |--------+------------------+---------------------------|
      | yes    | ?                | dir/[org-folder/org-file] |
      | no     | error?           | dir (as file or folder)   |
      | file   | tangle to TD+dir | tangle to TD+dir          |
      |--------+------------------+---------------------------|

Cheers,

Phil
From 360938b43a9c6a731114840c9b6db7c79f786116 Mon Sep 17 00:00:00 2001
From: Phil Estival <p...@7d.nz>
Date: Sat, 13 Jul 2024 14:46:08 +0200
Subject: [PATCH] add header-arg :tangle-directory declares a directory or a
 list of directories as parent(s) to the :tangle argument

---
 lisp/ob-tangle.el              | 16 ++++++--
 testing/lisp/test-ob-tangle.el | 72 +++++++++++++++++++++++++++++++++-
 2 files changed, 84 insertions(+), 4 deletions(-)

diff --git a/lisp/ob-tangle.el b/lisp/ob-tangle.el
index c89763efa..c494571dc 100644
--- a/lisp/ob-tangle.el
+++ b/lisp/ob-tangle.el
@@ -269,11 +269,20 @@ matching a regular expression."
 	     (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"))))
+            (dirs (cdr (assq :tangle-directory (nth 2 (org-babel-get-src-block-info)))))
 	    path-collector
-            (source-file buffer-file-name))
-	(mapc ;; map over file-names
+      (source-file buffer-file-name))
+
+        (setq dirs (cl-case (type-of dirs)
+                     (string (list dirs))
+                     (cons dirs)
+                     (symbol '(nil))))
+
+	(dolist (dir dirs) ; iterate the n-tangle group
+          (progn
+	(mapc ; map over directories
 	 (lambda (by-fn)
-	   (let ((file-name (car by-fn)))
+	   (let ((file-name (concat dir (car by-fn))))
 	     (when file-name
                (let ((lspecs (cdr by-fn))
 		     (fnd (file-name-directory file-name))
@@ -354,6 +363,7 @@ matching a regular expression."
 	 (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
diff --git a/testing/lisp/test-ob-tangle.el b/testing/lisp/test-ob-tangle.el
index e13bca0cb..a725cdb14 100644
--- a/testing/lisp/test-ob-tangle.el
+++ b/testing/lisp/test-ob-tangle.el
@@ -27,6 +27,7 @@
 
 (require 'subr-x)
 (require 'ob-tangle)
+(require 'find-file)
 (require 'org)
 
 ;; TODO
@@ -660,7 +661,13 @@ another block
 
 #+begin_src emacs-lisp :tangle ~/../../tmp/absolute.el
 \"H2: :tangle ~/../../tmp/absolute.el\"
-#+end_src"
+#+end_src
+
+#+begin_src emacs-lisp :tangle-directory '(\"/tmp/a/\" \"tmp/b/\") :tangle multiple.el
+\"H2: :tangle /tmp/multiple.el\"
+#+end_src
+
+"
                     `((?a . ,el-file-abs)
                       (?r . ,el-file-rel))))
       ;; We check the collected blocks to tangle by counting equal
@@ -699,6 +706,7 @@ another block
           (should (equal
                    (funcall normalize-expected-targets-alist
                             `(("/tmp/absolute.el" . 4)
+                              ("/tmp/multiple.el" . 1)
                               ("relative.el" . 5)
                               ;; Default :tangle header now also
                               ;; points to the file name derived from the name of
@@ -707,6 +715,68 @@ another block
                    (funcall count-blocks-in-target-files
                             (org-babel-tangle-collect-blocks)))))))))
 
+(ert-deftest ob-tangle/directory ()
+  "Test if ob-tangle/directory works correctly for one directory."
+  (should
+   (equal '("1")
+          (let* (
+                 (dir (make-temp-file "org-tangle-dir-test-" t))
+                 (filename (md5(format "%s" (current-time))))
+                 (file (concat dir "/" filename))
+                 )
+            (unwind-protect
+                (progn
+                  (org-test-with-temp-text-in-file
+                      (format "
+#+begin_src elisp :tangle-directory %s :tangle /%s <point>
+1
+#+end_src
+" dir filename)
+                    (let ((org-babel-noweb-error-all-langs nil)
+                          (org-babel-noweb-error-langs nil))
+                      (org-babel-tangle '(4))))
+
+                    (with-temp-buffer
+                      (insert-file-contents file)
+                      (org-split-string (buffer-string))))
+
+            (delete-file file)))
+          )))
+
+
+(ert-deftest ob-tangle/multiple-directories ()
+  "Test if ob-tangle/directory works correctly for multiple directory."
+  (should
+   (equal '("1" "1")
+          (let* (
+                 (dir1 (make-temp-file "org-tangle-dir-test-" t))
+                 (dir2 (make-temp-file "org-tangle-dir-test-" t))
+                 (filename (md5(format "%s" (current-time))))
+                 (file1 (concat dir1 "/" filename))
+                 (file2 (concat dir2 "/" filename))
+                 )
+            (unwind-protect
+                (progn
+                  (org-test-with-temp-text-in-file
+                      (format "
+#+begin_src elisp :tangle-directory '(\"%s\" \"%s\") :tangle /%s <point>
+1
+#+end_src
+" dir1 dir2 filename)
+                    (let ((org-babel-noweb-error-all-langs nil)
+                          (org-babel-noweb-error-langs nil))
+                      (org-babel-tangle '(4))))
+
+                    (with-temp-buffer
+                      (insert-file-contents file1)
+                      (insert-file-contents file2)
+                      (org-split-string (buffer-string))))
+              (progn
+                (delete-file file1)
+                (delete-file file2))))
+          )))
+
+
 (provide 'test-ob-tangle)
 
 ;;; test-ob-tangle.el ends here
-- 
2.39.2

Reply via email to