From mboxrd@z Thu Jan 1 00:00:00 1970 From: Aaron Ecay Subject: Re: [RFC] [PATCH] ob-core.el: allow the auto-generation of output file names for src blocks. Date: Sun, 27 Apr 2014 22:18:23 -0400 Message-ID: <8761lugqyi.fsf@gmail.com> References: <1398196476-4773-1-git-send-email-aaronecay@gmail.com> <87bnvt2h6r.fsf@bzg.ath.cx> <87d2g92au5.fsf@gmail.com> <8738h49u2g.fsf@gmail.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Return-path: Received: from eggs.gnu.org ([2001:4830:134:3::10]:52788) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Web9S-000636-Dn for emacs-orgmode@gnu.org; Sun, 27 Apr 2014 22:18:44 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Web9M-0002PK-LR for emacs-orgmode@gnu.org; Sun, 27 Apr 2014 22:18:38 -0400 In-Reply-To: <8738h49u2g.fsf@gmail.com> List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Sender: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org To: Eric Schulte , Bastien Cc: emacs-orgmode@gnu.org --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hi Eric, Bastien, Achim, Thanks so much for the feedback. I=E2=80=99ve adopted the :file-ext approa= ch suggested by Bastien, leaving the previous default behavior in place for blocks with a :file argument. 2014ko apirilak 22an, Eric Schulte-ek idatzi zuen: [...] > One option might be to borrow naming behavior from the comment > functionality in ob-tangle which looks like the following (from line 426 > in ob-tangle.el). > > (let (... > (source-name > (intern (or (nth 4 info) ; explicit #+name: > (format "%s:%d" ; constructed from header and posit= ion > (or (ignore-errors (nth 4 (org-heading-compone= nts))) > "No heading") > block-counter)))) > ...)) I=E2=80=99m not sure I like this approach. It relies on counting source blocks, so an addition/deletion of a block could change the index. I=E2=80=99m worried that this can lead to the accumulation of many output files: heading:1.ext, heading:2.ext, ... all with no clear indication of what block they were spawned by. It would also be possible for the result links in the buffer to become inconsistent with the actual block:auto-generated name mapping. I think I would prefer the code in this patch to do nothing in this case (not create a :file value), but for language-specific code that needs a :file to raise an error to prompt the user to add a name. > >> >> 2. should :output-dir apply to the :file case as well? >> > > If you mean "should :output-dir be used as the base when :file is a > relative pathname" then I'd say "yes", and I think if this isn't the > current behavior then the current behavior should be changed. Achim raises a backwards compatibility concern. I am not sure how serious it is: the default settings (no :output-dir) are backwards compatible, and if users set that arg we ought to just give them what they ask for. Nonetheless, the new version of the patch conservatively obeys Achim=E2=80= =99s suggestion. I can change this to your suggestion, if that is the consensus. To address a comment from Bastien: :output-dir accepts absolute as well as relative directory names. Referring to a =E2=80=9Csubdirectory=E2=80=9D= was a mistake on my part; the docs in the new patch should be clearer. The updated patch (now with docs and tests) is attached to this email. Thanks again, -- Aaron Ecay --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=0001-ob-core.el-allow-the-auto-generation-of-output-file-.patch >From 4b428820432752117c60b79da0a79fd4e50e4ba1 Mon Sep 17 00:00:00 2001 From: Aaron Ecay Date: Tue, 22 Apr 2014 15:13:48 -0400 Subject: [PATCH] ob-core.el: allow the auto-generation of output file names for src blocks. * lisp/ob-core.el (org-babel-generate-file-param): New function. (org-babel-get-src-block-info): Use it. * testing/lisp/test-ob.el (test-org-babel/file-ext-and-output-dir): New test. * doc/org.texi (Specific header arguments): Add doc for :file-ext and :output-dir header args. --- doc/org.texi | 27 +++++++++++++++++++++++++++ lisp/ob-core.el | 34 ++++++++++++++++++++++++++++++++++ testing/examples/babel.org | 34 ++++++++++++++++++++++++++++++++++ testing/lisp/test-ob.el | 14 ++++++++++++++ 4 files changed, 109 insertions(+) diff --git a/doc/org.texi b/doc/org.texi index 2546be1..79cc044 100644 --- a/doc/org.texi +++ b/doc/org.texi @@ -14406,6 +14406,8 @@ argument in lowercase letters. The following header arguments are defined: be collected and handled * file:: Specify a path for file output * file-desc:: Specify a description for file results +* file-ext:: Specify an extension for file output +* output-dir:: Specify a directory to write file output to * dir:: Specify the default (possibly remote) directory for code block execution * exports:: Export code and/or results @@ -14840,6 +14842,31 @@ description for file code block results which are inserted as Org mode links with no value the link path will be placed in both the ``link'' and the ``description'' portion of the Org mode link. +@node file-ext +@subsubsection @code{:file-ext} +@cindex @code{:file-ext}, src header argument + +The value of the @code{:file-ext} header argument is used to provide an +extension to write the file output to. It is combined with the +@code{#+NAME:} of the source block and the value of the @ref{output-dir} +header argument to generate a complete file name. + +This header arg will be overridden by @code{:file}, and thus has no effect +when the latter is specified. + +@node output-dir +@subsubsection @code{:output-dir} +@cindex @code{:output-dir}, src header argument + +The value of the @code{:output-dir} header argument is used to provide a +directory to write the file output to. It may specify an absolute directory +(beginning with @code{/}) or a relative directory (without @code{/}). It is +combined with the @code{#+NAME:} of the source block and the value of the +@ref{output-dir} header argument to generate a complete file name. + +This header arg will be overridden by @code{:file}, and thus has no effect +when the latter is specified. + @node dir @subsubsection @code{:dir} and remote execution @cindex @code{:dir}, src header argument diff --git a/lisp/ob-core.el b/lisp/ob-core.el index 1348f04..4a3683d 100644 --- a/lisp/ob-core.el +++ b/lisp/ob-core.el @@ -283,6 +283,8 @@ Returns a list ;; resolve variable references and add summary parameters (when (and info (not light)) (setf (nth 2 info) (org-babel-process-params (nth 2 info)))) + (when info + (setf (nth 2 info) (org-babel-generate-file-param name (nth 2 info)))) (when info (append info (list name indent head))))) (defvar org-babel-exp-reference-buffer nil @@ -2890,6 +2892,38 @@ For the format of SAFE-LIST, see `org-babel-safe-header-args'." (member (cdr pair) (cdr entry))) (t nil))))))) +(defun org-babel-generate-file-param (src-name params) + "Calculate the filename for source block results. + +The directory is calculated from the :output-dir property of the +source block; if not specified, use the current directory. + +If the source block has a #+NAME and the :file parameter does not +contain any period characters, then the :file parameter is +treated as an extension, and the output file name is the +concatenation of the directory (as calculated above), the block +name, a period, and the parameter value as a file extension. +Otherwise, the :file parameter is treated as a full file name, +and the output file name is the directory (as calculated above) +plus the parameter value." + (let* ((file-cons (assq :file params)) + (file-ext-cons (assq :file-ext params)) + (file-ext (cdr-safe file-ext-cons)) + (dir (or (cdr-safe (assq :output-dir params)) ""))) + ;; Only operate if: + ;; 1. :file is not given + ;; 2. :file-ext is given + ;; 3. the source block has a #+name + (if (and (not file-cons) file-ext src-name) + (progn + ;; Create the :output-dir if it does not exist + (when (and file-ext (not (string= dir ""))) + (make-directory dir t) + (unless (string-match "/\\'" dir) + (setq dir (concat dir "/")))) + (cons (cons :file (concat dir src-name "." file-ext)) params)) + ;; Otherwise return params unmodified + params))) ;;; Used by backends: R, Maxima, Octave. (defun org-babel-graphical-output-file (params) diff --git a/testing/examples/babel.org b/testing/examples/babel.org index 449824f..68ba65a 100644 --- a/testing/examples/babel.org +++ b/testing/examples/babel.org @@ -458,3 +458,37 @@ function definition "0")))) (format "elisp a:%d, b:%d, c:%d, d:%d, e:%d" a b c d e) #+END_SRC + +* =:file-ext= and =:output-dir= header args + :PROPERTIES: + :ID: 93573e1d-6486-442e-b6d0-3fedbdc37c9b + :END: +#+name: file-ext-basic +#+BEGIN_SRC emacs-lisp :file-ext txt +nil +#+END_SRC + +#+name: file-ext-dir-relative +#+BEGIN_SRC emacs-lisp :file-ext txt :output-dir foo +nil +#+END_SRC + +#+name: file-ext-dir-relative-slash +#+BEGIN_SRC emacs-lisp :file-ext txt :output-dir foo/ +nil +#+END_SRC + +#+name: file-ext-dir-absolute +#+BEGIN_SRC emacs-lisp :file-ext txt :output-dir /tmp +nil +#+END_SRC + +#+name: file-ext-file-wins +#+BEGIN_SRC emacs-lisp :file-ext txt :file foo.bar +nil +#+END_SRC + +#+name: file-ext-file-wins2 +#+BEGIN_SRC emacs-lisp :output-dir xxx :file foo.bar +nil +#+END_SRC diff --git a/testing/lisp/test-ob.el b/testing/lisp/test-ob.el index c0ca493..fb791d6 100644 --- a/testing/lisp/test-ob.el +++ b/testing/lisp/test-ob.el @@ -1237,6 +1237,20 @@ echo \"$data\" (org-babel-execute-src-block))) (should (= noweb-expansions-in-cache-var 2))))) +(ert-deftest test-org-babel/file-ext-and-output-dir () + (org-test-at-id "93573e1d-6486-442e-b6d0-3fedbdc37c9b" + (macrolet ((at-next (&rest body) + `(progn + (org-babel-next-src-block) + (save-match-data ,@body)))) + (at-next (should (equal "file-ext-basic.txt" (cdr (assq :file (nth 2 (org-babel-get-src-block-info t))))))) + (at-next (should (equal "foo/file-ext-dir-relative.txt" (cdr (assq :file (nth 2 (org-babel-get-src-block-info t))))))) + (at-next (should (equal "foo/file-ext-dir-relative-slash.txt" (cdr (assq :file (nth 2 (org-babel-get-src-block-info t))))))) + (at-next (should (equal "/tmp/file-ext-dir-absolute.txt" (cdr (assq :file (nth 2 (org-babel-get-src-block-info t))))))) + (at-next (should (equal "foo.bar" (cdr (assq :file (nth 2 (org-babel-get-src-block-info t))))))) + (at-next (should (equal "foo.bar" (cdr (assq :file (nth 2 (org-babel-get-src-block-info t))))))) + ))) + (provide 'test-ob) ;;; test-ob ends here -- 1.9.2 --=-=-=--