Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,18 +136,21 @@ In general, it makes the whole experience of using org mode notebooks for infrsa
This package works with "targets" defined at the top of the file, which also appear in heading tags:

```org
#+TARGET: /ssh:example1.com: (server1)
#+TARGET: /ssh:example2.com: (server2)
#+TARGET: server1 /ssh:example1.com:
#+TARGET: server2 /ssh:example2.com:

* Do something on server1 :server1:
* Do something on server2 :server2:
```

Each `#+TARGET` names a tag and then its target, like org's `#+LINK`. The older
form, `#+TARGET: /ssh:example1.com: (server1)`, still works.

Source code blocks under a heading tag that matches a target (a "target tag") execute in on the server, instead of locally:

```org
#+TARGET: /ssh:example1.com: (server1)
#+TARGET: /ssh:example2.com: (server2)
#+TARGET: server1 /ssh:example1.com:
#+TARGET: server2 /ssh:example2.com:

* Do something on server1 :server1:

Expand Down Expand Up @@ -214,7 +217,7 @@ processing the output of the code block.
For example, let's say we have a `TARGET` that points to a Podman container in a server:

```org
#+TARGET: /ssh:server.com|podman:my-container: (container)
#+TARGET: container /ssh:server.com|podman:my-container:
```

We can chain together a remote command and a local processing step as follows:
Expand Down Expand Up @@ -242,7 +245,7 @@ This will work even if the `jq` command is not installed in the container :)
A `#+TARGET` value can be a noweb-style reference:

```org
#+TARGET: <<server-target()>> (server)
#+TARGET: server <<server-target()>>

#+name: input-instance
: app1
Expand Down Expand Up @@ -302,7 +305,7 @@ When `devops-enable-session-async` is enabled, blocks are executed as if you had
the `session` and `async` headers yourself. For example,

```org
#+TARGET: /ssh:example.com: (example)
#+TARGET: example /ssh:example.com:

* Update packages :example:

Expand Down
25 changes: 25 additions & 0 deletions devops-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,31 @@ The directory is removed afterwards."
"<<t(INSTANCE=\"a b\")>> (server)")
'("server" . "<<t(INSTANCE=\"a b\")>>"))))

(ert-deftest devops--parse-target-keyword-link-style-test ()
"A #+TARGET value may name its tag first, like #+LINK."
(should (equal (devops--parse-target-keyword "server1 /ssh:host1:")
'("server1" . "/ssh:host1:")))
(should (equal (devops--parse-target-keyword "local /srv/app/")
'("local" . "/srv/app/")))
(should (equal (devops--parse-target-keyword "server <<server-target()>>")
'("server" . "<<server-target()>>")))
(should (equal (devops--parse-target-keyword
"server <<t(INSTANCE=\"a b\")>>")
'("server" . "<<t(INSTANCE=\"a b\")>>")))
;; A relative directory in the old form is not read as a tag.
(should (equal (devops--parse-target-keyword "app (local)")
'("local" . "app")))
(should (null (devops--parse-target-keyword "server"))))

(ert-deftest devops-target-tag-alist-mixed-test ()
"Both #+TARGET forms may appear in one buffer."
(devops-test--with-org
(concat "#+TARGET: /srv/one/ (t1)\n"
"#+TARGET: t2 /srv/two/\n\n"
"* Heading\n")
(should (equal (devops-target-tag-alist)
'(("t1" . "/srv/one/") ("t2" . "/srv/two/"))))))

(ert-deftest devops-target-ref-test ()
"`devops-target-ref' tells a reference from a literal target."
(should (equal (devops-target-ref "<<server-target()>>") "server-target()"))
Expand Down
18 changes: 10 additions & 8 deletions devops.el
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
;;
;; `devops.el' adds TARGET syntax to org-babel:
;;
;; #+TARGET: /ssh:web1.example.com: (web)
;; #+TARGET: /ssh:db1.example.com: (db)
;; #+TARGET: web /ssh:web1.example.com:
;; #+TARGET: db /ssh:db1.example.com:
;;
;; * Check the web server :web:
;; #+begin_src sh
Expand Down Expand Up @@ -138,15 +138,17 @@ reference, a dynamic target, tangling, a drift check. Meaningful in
`org-babel-after-execute-hook'."
(not devops--inhibit-async))

;; Maybe it would make sense to follow the #+LINK syntax?
;; #+TARGET: server /ssh:example1.com:

(defun devops--parse-target-keyword (value)
"Parse a #+TARGET VALUE like \"target1 (source)\" into (TAG . TARGET).
"Parse a #+TARGET VALUE into (TAG . TARGET).
VALUE is \"TAG TARGET\", like org's #+LINK, or the older \"TARGET (TAG)\".
TARGET is a directory, a TRAMP prefix, or a reference to a named block
written in noweb's brackets, `<<NAME>>' or `<<NAME(ARGS)>>'."
(when (string-match "\\`\\(<<.*>>\\|[^ ]+\\) +(\\([^)]+\\))\\'" value)
(cons (match-string 2 value) (match-string 1 value))))
(let ((target "\\(<<.*>>\\|[^ ]+\\)"))
(cond
((string-match (concat "\\`" target " +(\\([^)]+\\))\\'") value)
(cons (match-string 2 value) (match-string 1 value)))
((string-match (concat "\\`\\([[:alnum:]_@#%]+\\) +" target "\\'") value)
(cons (match-string 1 value) (match-string 2 value))))))

(defun devops--org-keywords (key)
"Return all values for keyword KEY as a list."
Expand Down
8 changes: 4 additions & 4 deletions examples/1_commands.org
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#+PROPERTY: header-args:sh :results output
#+TARGET: /ssh:example1.com: (server1)
#+TARGET: /ssh:example2.com: (server2)
#+TARGET: server1 /ssh:example1.com:
#+TARGET: server2 /ssh:example2.com:
#+TITLE: Running server commands

=devops.el= helps you run commands on one or more named targets by declaring them at the the top of the file.

#+begin_example
#+TARGET: /ssh:example1.com: (server1)
#+TARGET: /ssh:example2.com: (server2)
#+TARGET: server1 /ssh:example1.com:
#+TARGET: server2 /ssh:example2.com:
#+end_example

Normally, org-babel runs commands on servers whenever the =:dir= header argument
Expand Down
4 changes: 2 additions & 2 deletions examples/2_tangle.org
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#+TARGET: /ssh:example1.com: (server1)
#+TARGET: /ssh:example2.com: (server2)
#+TARGET: server1 /ssh:example1.com:
#+TARGET: server2 /ssh:example2.com:
#+TITLE: Example 2: Tangle files

=devops.el= helps you create files in remote servers.
Expand Down
Loading