3

I want to maintain a single org file which contained a plethora of different init files (.bashrc, .profile, .tmux etc that type of thing). Here's a portion:-

#+PROPERTY: header-args :tangle yes :comments no

* bashrc
  :PROPERTIES:
  :header-args+: :tangle "./DotFiles/.bashrc"
  :END:
** bashrc 1
   #+begin_src shell
     # -*- mode: read-only -*-
     # ~/.bashrc: executed by bash(1) for non-login shells.
     # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
     # for examples

Now when I tangle (C-c C-v t), the bashrc is correctly tangled and written to ./DotFiles/.bashrc. Notice the first line inside the #+begin_src :-

 # -*- mode: read-only -*-

Now, this works in that when I open that .bashrc in emacs then it's readonly, a subtle reminder that I need to edit the master org-file.

Currently I need to add that to each and every dotfile section I have in my master org file. Is there a way to specify a global "first line" in each exported file? I would have thought a

header-args: :comments "# -*- mode: read-only -*-"

would do that but alas not. Is there cleaner way to do this than the way I'm currently doing it?

3

#+PROPERTY: header-args:conf :tangle-mode (identity #o444)

Sets the files as read-only (not just for emacs, but for any editor). Then, each block can be:

#+BEGIN_SRC conf :tangle ~/.file_rc
#+END_SRC

Repeat for bash and other specific languages if you want them in BEGIN_SRC bash blocks rather than conf blocks.

Tested on Org mode version 9.3.7 (9.3.7-18-g093b47-elpaplus @ ~/.emacs.d/elpa/org-plus-contrib-20200810/)

| improve this answer | |
  • seems a nice solution but it doesnt work for me. I write out the src blocks eg to .bashrc and it's still -rw-r--r-- 1 rgr rgr 2024 Aug 11 08:18 .bashrc. I did C-c C-c on property line and also restarted emacs. May I ask if you tested this as I used your exactlines (changing filename) – RichieHH Aug 11 at 6:20
  • 1
    I tested this answer and it works for me (with the tangle-mode header specified either on the code block or in a #+PROPERTY header) on the following versions: Org mode version 9.3.7 (release_9.3.7-705-gea9463) -- GNU Emacs 28.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 2.24.32, cairo version 1.16.0) of 2020-06-15 -- Linux 5.5.13-200.fc31.x86_64 #1 SMP Wed Mar 25 21:55:30 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux – NickD Aug 11 at 13:36
  • Hmm. No joy. 9.3.7 Org mode. Emacs 27. I deleted DotFiles and re exported (C-c C-v t) to an empty dir. Could this maybe linked to me using zsh? /home/rgr/.emacs.d/linux-init/DotFiles: total used in directory 32 available 171.7 GiB drwxr-xr-x 2 rgr rgr 4096 Aug 11 21:39 . drwxr-xr-x 4 rgr rgr 4096 Aug 11 21:39 .. -rw-r--r-- 1 rgr rgr 2024 Aug 11 21:39 .bashrc -rw-r--r-- 1 rgr rgr 938 Aug 11 21:39 .profile -rw-r--r-- 1 rgr rgr 2238 Aug 11 21:39 .tmux.conf -rw-r--r-- 1 rgr rgr 37 Aug 11 21:39 .zprofile -rw-r--r-- 1 rgr rgr 5227 Aug 11 21:39 .zshrc – RichieHH Aug 11 at 19:41
  • share MWE - two line BEGIN_SRC & END_SRC... – mankoff Aug 11 at 23:40
  • 1
    There is nothing wrong with the file: they are all tangled with mode 444 for me. Something else is interfering. – NickD Aug 12 at 18:32
0

Define a function to add the string and add it to org-babel-tangle-body-hook:

#+PROPERTY: header-args :tangle yes :comments no

* bashrc
  :PROPERTIES:
  :header-args+: :tangle "./DotFiles/.bashrc"
  :END:
** bashrc 1
   #+begin_src shell
     # ~/.bashrc: executed by bash(1) for non-login shells.
     # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
     # for examples
   #+end_src


* Code

#+begin_src emacs-lisp
  (defun ndk/add-read-only ()
    (goto-char (point-min))
    (insert "# -*- mode: read-only -*-\n\n"))

 (add-hook 'org-babel-tangle-body-hook #'ndk/add-read-only)
#+end_src

#+begin_src emacs-lisp
  (remove-hook 'org-babel-tangle-body-hook #'ndk/add-read-only)
#+end_src

You will need to remove the function from the hook afterwards, hence the second code block.

| improve this answer | |
  • 1
    Thanks. Certainly a good technique for adding other generic comments/headers to output files. For this case, I would prefer the previous solution from Mankoff if I can get it working as it's read-only for all editors. – RichieHH Aug 11 at 11:54
  • 1
    I agree. I upvoted his answer :-) – NickD Aug 11 at 13:27
0

Use :noweb weaving to include common snippets of code between blocks

#+PROPERTY: header-args :tangle yes :comments no :noweb yes

#+NAME: common-mode-line
#+BEGIN_SRC shell :eval never :tangle no
  # -*- mode: read-only -*-
#+END_SRC

* bashrc
  :PROPERTIES:
  :header-args+: :tangle "./DotFiles/.bashrc"
  :END:
** bashrc 1
   #+begin_src shell
     <<common-mode-line>>
     # ~/.bashrc: executed by bash(1) for non-login shells.
     # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
     # for examples
   #+end_src

If you want to get really fancy with metaprogramming, you can use :noweb features to include the results of code block instead.

e.g.

#+NAME: common-mode-line-meta
#+BEGIN_SRC shell :tangle no :var MODE_LINE="mode: read-only"
  echo "# -*- ${MODE_LINE}  -*-"
#+END_SRC


* bashrc
  :PROPERTIES:
  :header-args+: :tangle "./DotFiles/.bashrc-meta"
  :END:
** bashrc 1
   #+begin_src shell
     <<common-mode-line-meta()>>
     # ~/.bashrc: executed by bash(1) for non-login shells.
     # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
     # for examples
   #+end_src

This would allow you to customize the mode by passing parameter via the noweb statement <<common-mode-line-meta(MODE_LINE="mode: Shell-script")>> which would output # -*- mode: Shell-script -*- at top of file instead.

I use results from custom code blocks like this to create data structures for yaml, json, ruby, python and perl files from org-tables for Literate DevOps.

Note: If you do not want to add noweb syntax to each code block by hand then just add common-mode-line-meta code block and then add :prologue (org-sbe common-mode-line-meta) to your header-args statement.

Thanks for asking your question!


This answer was tested using:
emacs version: GNU Emacs 25.2.1
org-mode version: 9.1.2

| improve this answer | |
-1

Not an answer per se, but the problem seems to be with tangling through a symlink. In my example above DotFiles was a symlink.

When I tangled directly to the "hard" file then the identity worked.

I've been unable to find out why this is but am happy I can work around it.

Update: 15/8/2020

The plot thickens. It's now apparent that the reason the identify "didn't work" is... Dropbox. It does indeed work but Dropbox switches it back to o644 almost immediately. I've been unable to find out why other than assuming Dropbox runs as user and must have user write permissions.

enter image description here

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.