Prevent export to file from overwriting current file

* lisp/ox.el (org-export-output-file-name): Add a protection when
  output file name is the same as the original org.
* testing/lisp/test-ox.el: Add tests.
This commit is contained in:
Nicolas Goaziou 2013-02-15 15:06:01 +01:00
parent 5bceb62142
commit a8e48bd3a8
2 changed files with 75 additions and 32 deletions

View File

@ -2962,38 +2962,44 @@ directory.
When optional argument VISIBLE-ONLY is non-nil, don't export
contents of hidden elements.
Return file name as a string, or nil if it couldn't be
determined."
(let ((base-name
;; File name may come from EXPORT_FILE_NAME subtree property,
;; assuming point is at beginning of said sub-tree.
(file-name-sans-extension
(or (and subtreep
(org-entry-get
(save-excursion
(ignore-errors (org-back-to-heading) (point)))
"EXPORT_FILE_NAME" t))
;; File name may be extracted from buffer's associated
;; file, if any.
(let ((visited-file (buffer-file-name (buffer-base-buffer))))
(and visited-file (file-name-nondirectory visited-file)))
;; Can't determine file name on our own: Ask user.
(let ((read-file-name-function
(and org-completion-use-ido 'ido-read-file-name)))
(read-file-name
"Output file: " pub-dir nil nil nil
(lambda (name)
(string= (file-name-extension name t) extension))))))))
;; Build file name. Enforce EXTENSION over whatever user may have
;; come up with. PUB-DIR, if defined, always has precedence over
;; any provided path.
(cond
(pub-dir
(concat (file-name-as-directory pub-dir)
(file-name-nondirectory base-name)
extension))
((file-name-absolute-p base-name) (concat base-name extension))
(t (concat (file-name-as-directory ".") base-name extension)))))
Return file name as a string."
(let* ((visited-file (buffer-file-name (buffer-base-buffer)))
(base-name
;; File name may come from EXPORT_FILE_NAME subtree
;; property, assuming point is at beginning of said
;; sub-tree.
(file-name-sans-extension
(or (and subtreep
(org-entry-get
(save-excursion
(ignore-errors (org-back-to-heading) (point)))
"EXPORT_FILE_NAME" t))
;; File name may be extracted from buffer's associated
;; file, if any.
(and visited-file (file-name-nondirectory visited-file))
;; Can't determine file name on our own: Ask user.
(let ((read-file-name-function
(and org-completion-use-ido 'ido-read-file-name)))
(read-file-name
"Output file: " pub-dir nil nil nil
(lambda (name)
(string= (file-name-extension name t) extension)))))))
(output-file
;; Build file name. Enforce EXTENSION over whatever user
;; may have come up with. PUB-DIR, if defined, always has
;; precedence over any provided path.
(cond
(pub-dir
(concat (file-name-as-directory pub-dir)
(file-name-nondirectory base-name)
extension))
((file-name-absolute-p base-name) (concat base-name extension))
(t (concat (file-name-as-directory ".") base-name extension)))))
;; If writing to OUTPUT-FILE would overwrite original file, append
;; EXTENSION another time to final name.
(if (and visited-file (file-equal-p visited-file output-file))
(concat output-file extension)
output-file)))
(defun org-export-expand-include-keyword (&optional included dir)
"Expand every include keyword in buffer.

View File

@ -421,6 +421,43 @@ text
(should (equal (org-export-as 'test nil nil 'body-only) "Text\n"))
(should (equal (org-export-as 'test) "BEGIN\nText\nEND")))))
(ert-deftest test-org-export/output-file-name ()
"Test `org-export-output-file-name' specifications."
;; Export from a file: name is built from original file name.
(should
(org-test-with-temp-text-in-file "Test"
(equal (concat (file-name-as-directory ".")
(file-name-nondirectory
(file-name-sans-extension (buffer-file-name))))
(file-name-sans-extension (org-export-output-file-name ".ext")))))
;; When exporting to subtree, check EXPORT_FILE_NAME property first.
(should
(org-test-with-temp-text-in-file
"* Test\n :PROPERTIES:\n :EXPORT_FILE_NAME: test\n :END:"
(equal (org-export-output-file-name ".ext" t) "./test.ext")))
;; From a buffer not associated to a file, too.
(should
(org-test-with-temp-text
"* Test\n :PROPERTIES:\n :EXPORT_FILE_NAME: test\n :END:"
(equal (org-export-output-file-name ".ext" t) "./test.ext")))
;; When provided name is absolute, preserve it.
(should
(org-test-with-temp-text
(format "* Test\n :PROPERTIES:\n :EXPORT_FILE_NAME: %s\n :END:"
(expand-file-name "test"))
(file-name-absolute-p (org-export-output-file-name ".ext" t))))
;; When PUB-DIR argument is provided, use it.
(should
(org-test-with-temp-text-in-file "Test"
(equal (file-name-directory
(org-export-output-file-name ".ext" nil "dir/"))
"dir/")))
;; When returned name would overwrite original file, add EXTENSION
;; another time.
(should
(org-test-at-id "75282ba2-f77a-4309-a970-e87c149fe125"
(equal (org-export-output-file-name ".org") "./normal.org.org"))))
(ert-deftest test-org-export/expand-include ()
"Test file inclusion in an Org buffer."
;; Error when file isn't specified.