Hi, I noticed that during grouping of blocks to tangle some of them can
overwrite each other if they have the same target file, but in different
format (relative vs absolute).

Consider this example (part of example.org file in the attachment):

  * 1st explicit :tangle yes
  #+begin_src emacs-lisp :tangle yes
    "1st explicit :tangle yes"
  #+end_src
  * 1st implicit default
  #+begin_src emacs-lisp
    "1st implicit :tangle no"
  #+end_src

If we call `org-babel-tangle-file' with target-file arg equal to
"/path/to/example.el" (e.g. `org-babel-load-file' does that), then
target file name for the first block will be "example.el" and
"/path/to/example.el" for the second block. It appears to be crucial in
`org-babel-tangle-collect-blocks' [1]:

  ;; `org-babel-map-src-blocks' runs this part on each source block
  (let* ((block (org-babel-tangle-single-block counter))
         (src-tfile (cdr (assq :tangle (nth 4 block))))
         (file-name (org-babel-effective-tangled-filename
                     (nth 1 block) src-lang src-tfile))
         (by-fn (assoc file-name blocks)))
    (if by-fn (setcdr by-fn (cons (cons src-lang block) (cdr by-fn)))
      (push (cons file-name (list (cons src-lang block))) blocks)))

Current implementation of `org-babel-effective-tangled-filename' returns
relative file name if :tangle is "yes" or relative FILENAME. But if
:tangle happened to be absolute (as `org-babel-load-file' does), then
blocks with the same file name but one name is relative while the other is
absolute, will be treated as different and won't be group (see last tree
lines of code above).

As a result when blocks are returned to `org-babel-tangle' [2] one group
will overwrite the previous one, since their absolute file names are
equal.

I noticed two scenarious where such things happen (e.g. if running
`org-babel-tangle-file'):
- if target-file arg is equal to one of :tangle FILENAMEs and some
  blocks don't have :tangle argument, while other have :tangle
  FILENAME. As a result one of these groups will be lost.
- if target-file arg is equal to tangled original Org file and some
  blocks don't have :tangle argument, while other have :tangle
  "yes". As a result one of these groups will also be lost.

I attach example Org file and scratch code to reproduce both scenarious.

[1] [[file:lisp/ob-tangle.el::(file-name 
(org-babel-effective-tangled-filename][target file-name]]

[2] [[file:lisp/ob-tangle.el::org-babel-tangle-collect-blocks lang-re 
tangle-file))][blocks return]]

* 1st explicit :tangle yes
#+begin_src emacs-lisp :tangle yes
  "1st explicit :tangle yes"
#+end_src
* 1st explicit :tangle filename.el
#+begin_src emacs-lisp :tangle filename.el
  "1st explicit :tangle filename.el"
#+end_src
* 1st implicit default
#+begin_src emacs-lisp
  "1st implicit :tangle no"
#+end_src
* 2nd explicit :tangle yes
#+begin_src emacs-lisp :tangle yes
  "2nd explicit :tangle yes"
#+end_src
* explicit :tangle no
#+begin_src emacs-lisp :tangle no
  "explicit :tangle no"
#+end_src
* 2nd explicit :tangle filename.el
#+begin_src emacs-lisp :tangle filename.el
  "2nd explicit :tangle filename.el"
#+end_src
* 2nd implicit default
#+begin_src emacs-lisp
  "2nd implicit :tangle no"
#+end_src

Attachment: scratch.el
Description: scratch code to reproduce the bug

Reply via email to