Hey,

I am looking for a way to set permission on a file created from source
code block result when :file header argument is used. I was looking for
something like :tangle-mode but could not find anything. I wrote a patch
that does just that and it works for my small use case. It's a header
argument called :file-mode and can be used in the same way as
:tangle-mode.

Example usage:

#+BEGIN_SRC shell :results file :file script.sh :file-mode (identity #o755)
  echo "#!/bin/bash"
  echo "echo Hello World"
#+END_SRC

Is this a suitable way of doing it?

Best regards
John

>From a58d960092ad944e17e9b22f337379ed90638b65 Mon Sep 17 00:00:00 2001
From: John Herrlin <jherr...@gmail.com>
Date: Fri, 24 Jul 2020 13:45:18 +0200
Subject: [PATCH] ob-core: file-mode option in source code block arguments

* ob-core.el (org-babel-execute-src-block): Source code block header
argument :file-mode can set file permission if :file argument is provided
---
 doc/org-manual.org      | 12 ++++++++++++
 lisp/ob-core.el         |  5 ++++-
 testing/lisp/test-ob.el | 17 +++++++++++++++++
 3 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index b616446..2919139 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -17440,6 +17440,18 @@ default behavior is to automatically determine the result type.
   uses the generated file name for both the "link" and
   "description" parts of the link.
 
+  #+cindex: @samp{file-mode}, header argument
+  The =file-mode= header argument defines the file permission. For
+  example, to make a read-only file, use ‘:file-mode (identity
+  #o444)’. To make it executable, use ‘:file-mode (identity #o755)’
+
+  #+begin_example
+  ,#+BEGIN_SRC shell :results file :file script.sh :file-mode (identity #o755)
+    echo "#!/bin/bash"
+    echo "echo Hello World"
+  ,#+END_SRC
+  #+end_example
+
   #+cindex: @samp{sep}, header argument
   By default, Org assumes that a table written to a file has
   TAB-delimited output.  You can choose a different separator with
diff --git a/lisp/ob-core.el b/lisp/ob-core.el
index e798595..cc3e002 100644
--- a/lisp/ob-core.el
+++ b/lisp/ob-core.el
@@ -731,7 +731,10 @@ block."
 		    (with-temp-file file
 		      (insert (org-babel-format-result
 			       result
-			       (cdr (assq :sep params))))))
+			       (cdr (assq :sep params)))))
+		    ;; Set permissions if header argument `:file-mode' is provided
+		    (when (assq :file-mode params)
+		      (set-file-modes file (cdr (assq :file-mode params)))))
 		  (setq result file))
 		;; Possibly perform post process provided its
 		;; appropriate.  Dynamically bind "*this*" to the
diff --git a/testing/lisp/test-ob.el b/testing/lisp/test-ob.el
index 7c44622..c4aaad1 100644
--- a/testing/lisp/test-ob.el
+++ b/testing/lisp/test-ob.el
@@ -1746,6 +1746,23 @@ line 1
 		   (cdr (assq :file (nth 2 (org-babel-get-src-block-info t))))))
     ))
 
+(ert-deftest test-ob/file-mode ()
+  "Ensure that file have correct permissions."
+  (let* ((file       (org-babel-temp-file "file-mode-" ".sh"))
+	 (filename   (file-name-nondirectory file))
+	 (path       (file-name-directory file)))
+    (org-test-with-temp-text
+	(concat
+	 "#+BEGIN_SRC emacs-lisp :results file "
+	 ":file " filename " "
+	 ":output-dir " path " "
+	 ":file-mode (identity #o755)
+     nil
+     #+END_SRC")
+      (org-babel-execute-src-block))
+    (should (equal (file-modes file)
+		   493))))
+
 (ert-deftest test-ob-core/dir-mkdirp ()
   "Test :mkdirp with :dir header combination."
   (should-not
-- 
2.27.0

Reply via email to