Skip to content

Commit d1ae278

Browse files
committed
CLJ-2760 Add api to invoke an external function via the Clojure CLI
1 parent 65ea3e7 commit d1ae278

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
; Copyright (c) Rich Hickey. All rights reserved.
2+
; The use and distribution terms for this software are covered by the
3+
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4+
; which can be found in the file epl-v10.html at the root of this distribution.
5+
; By using this software in any fashion, you are agreeing to be bound by
6+
; the terms of this license.
7+
; You must not remove this notice, or any other, from this software.
8+
(ns clojure.tools.deps.interop
9+
"Functions for invoking Java processes and invoking tools via the Clojure CLI."
10+
(:require
11+
[clojure.java.process :as proc]
12+
[clojure.edn :as edn]))
13+
14+
(defn ^:dynamic invoke-tool
15+
"Invoke tool using Clojure CLI. Args (one of :tool-alias or :tool-name, and :fn
16+
are required):
17+
:tool-alias - Tool alias to invoke (keyword)
18+
:tool-name - Name of installed tool to invoke (string or symbol)
19+
:fn - Function (symbol)
20+
:args - map of args to pass to function
21+
22+
Options:
23+
:command - CLI command, default=\"clojure\"
24+
:preserve-envelope - if true, return the full invocation envelope, default=false"
25+
{:added "1.12"}
26+
[{:keys [tool-name tool-alias fn args command preserve-envelope]
27+
:or {command "clojure", preserve-envelope false}
28+
:as opts}]
29+
(when-not (or tool-name tool-alias) (throw (ex-info "Either :tool-alias or :tool-name must be provided" (or opts {}))))
30+
(when-not (symbol? fn) (throw (ex-info (str "fn should be a symbol " fn) (or opts {}))))
31+
(let [args (assoc args :clojure.exec/invoke :fn)
32+
_ (when (:debug opts) (println "args" args))
33+
command-strs [command (str "-T" (or tool-alias tool-name)) (pr-str fn) (pr-str args)]
34+
_ (when (:debug opts) (apply println "Invoking: " command-strs))
35+
envelope (edn/read-string (apply proc/exec command-strs))]
36+
(if preserve-envelope
37+
envelope
38+
(let [{:keys [tag val]} envelope
39+
parsed-val (edn/read-string val)]
40+
(if (= :ret tag)
41+
parsed-val
42+
(throw (ex-info (:cause parsed-val) (or parsed-val {}))))))))
43+
44+
(comment
45+
;; regular invocation, should return {:hi :there}
46+
(invoke-tool {:tool-alias :deps, :fn 'clojure.core/identity, :args {:hi :there}})
47+
48+
;; invocation throws, should return throwable map data
49+
(try
50+
(invoke-tool {:tool-alias :deps, :fn 'clojure.core/+, :args {:fail :here}})
51+
(catch clojure.lang.ExceptionInfo e (ex-data e)))
52+
53+
;; capture stdout in returned envelope
54+
(let [resp (invoke-tool {:tool-alias :deps,
55+
:fn 'list
56+
:args {:format :edn
57+
:clojure.exec/out :capture}
58+
:preserve-envelope true})]
59+
(edn/read-string (:out resp)))
60+
61+
)

0 commit comments

Comments
 (0)