Skip to content

Commit 6cf199f

Browse files
committed
Introduce --exec-fn cli option and functionality
This patch adds more superpowers to launchpad: it can now launch the first configured `:exec-fn` (and relative `:exec-args`). It does it by introducing a brand new exec-fn-steps var containing, among the others, the `exec-fn-eval-forms` step, which contains the logic for appending the correct `:eval-forms`. Note that this is a completely new code path and neither start nrepl nor hooks up the hot reloading facilities.
1 parent 3d0cabf commit 6cf199f

File tree

3 files changed

+67
-14
lines changed

3 files changed

+67
-14
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212

1313
- Add `--no-prefix` or `{:launchpad/options {:prefix false}}` to hide the
1414
start-of-line per-process prefix in the output
15+
- Introduce `--exec-fn` (or `{:launchpad/options {:exec-fn false}}`) and
16+
functionality that can launch the first configured `:exec-fn` (and
17+
relative `:exec-args`).
1518

1619
## Fixed
1720

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,30 @@ Most of the time you want to add extra steps either right before, or right after
255255
launchpad/start-process]
256256
launchpad/after-steps)})
257257
```
258+
259+
## Launch configured :exec-fn
260+
261+
Launchpad can also call the first found `:exec-fn` function (and relative `:exec-args`).
262+
263+
> [!TIP]
264+
> The `Aliases:` line in the summary shows the ordered list of processed aliases. Only the first `:exec-fn` is used.
265+
266+
For example, you can configure an `:mcp` alias (from bhauman/clojure-mcp) within `deps.local.edn` like this:
267+
268+
```clojure
269+
:aliases {:mcp {:extra-deps {org.slf4j/slf4j-nop {:mvn/version "2.0.16"}
270+
com.bhauman/clojure-mcp {:local/root "/path/to/clojure-mcp"}}
271+
:exec-fn clojure-mcp.main/start-mcp-server
272+
:exec-args {:port 7888}}}
273+
...
274+
```
275+
276+
and launchpad will be able to call `clojure-mcp.main/start-mcp-server` this way:
277+
278+
```
279+
$ launchpad --exec-fn mcp
280+
```
281+
258282
## Praise from Users
259283

260284
"This looks like a much easier way to get a new project up and running in a consistent and predictable manner where there is less likelihood of steps being missed or being different enough to cause confusion or additional cognitive load when switching projects. As you point out, also great for getting a team all working in a consistent configuration." -- Tim Cross, @theophilusx1

src/lambdaisland/launchpad.clj

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@
5353
"--[no-]debug-repl" {:doc "Include gfredericks/debug-repl dependency and middleware"}
5454
"--[no-]go" {:doc "Call (user/go) on boot"}
5555
"--[no-]namespace-maps" {:doc "Disable *print-namespace-maps* through nREPL middleware"}
56-
"--[no-]prefix" {:doc "Disable per-process prefix"}])
56+
"--[no-]prefix" {:doc "Disable per-process prefix"}
57+
"--[no-]exec-fn" {:doc "Parse and execute the first :exec-fn found"}])
5758

5859
(def library-versions
5960
(:deps (edn/read-string (slurp (io/resource "launchpad/deps.edn")))))
@@ -349,14 +350,28 @@
349350
(catch Exception e
350351
(println "(user/go) failed" e))))))
351352

352-
(defn run-nrepl-server [{:keys [nrepl-port nrepl-bind middleware] :as ctx}]
353+
(defn nrepl-server-eval-forms [{:keys [nrepl-port nrepl-bind middleware] :as ctx}]
353354
(-> ctx
354355
(update :requires conj 'nrepl.cmdline)
355356
(update :eval-forms (fnil conj [])
356357
`(nrepl.cmdline/-main "--port" ~(str nrepl-port)
357358
"--bind" ~(str nrepl-bind)
358359
"--middleware" ~(pr-str middleware)))))
359360

361+
(defn exec-fn-eval-forms [{:keys [aliases deps-edn] :as ctx}]
362+
(let [{:keys [alias exec-fn exec-args]}
363+
(->> aliases
364+
;; we use only the first alias where :exec-fn is defined
365+
(some #(when (get-in deps-edn [:aliases % :exec-fn])
366+
(-> (get-in deps-edn [:aliases %])
367+
(assoc :alias %)))))]
368+
(assert (and exec-fn (symbol? exec-fn))
369+
"Launchpad could not find any valid :exec-fn symbol, aborting...")
370+
(info (format "Executing %s from the %s alias" exec-fn alias))
371+
(-> ctx
372+
(update :requires conj (symbol (namespace exec-fn)))
373+
(update :eval-forms (fnil conj []) `(~exec-fn ~exec-args)))))
374+
360375
(defn register-watch-handlers [ctx handlers]
361376
(update ctx
362377
:watch-handlers
@@ -544,7 +559,7 @@
544559
(System/exit exit)))
545560
ctx))))))
546561

547-
(defn start-clojure-process [{:keys [aliases nrepl-port] :as ctx}]
562+
(defn start-clojure-process [ctx]
548563
(let [args (clojure-cli-args ctx)]
549564
(apply debug (map shellquote args))
550565
((run-process {:cmd args
@@ -566,7 +581,7 @@
566581
inject-aliases-as-property
567582
include-watcher
568583
print-summary
569-
run-nrepl-server])
584+
nrepl-server-eval-forms])
570585

571586
(def after-steps [wait-for-nrepl
572587
;; stuff that happens after the server is up
@@ -576,6 +591,14 @@
576591
[start-clojure-process]
577592
after-steps))
578593

594+
(def exec-fn-steps [handle-cli-args
595+
;; extra java flags
596+
disable-stack-trace-elision
597+
inject-aliases-as-property
598+
print-summary
599+
exec-fn-eval-forms
600+
start-clojure-process])
601+
579602
(def ^:deprecated start-process start-clojure-process)
580603

581604
(defn find-project-root []
@@ -609,17 +632,20 @@
609632
end-steps
610633
pre-steps
611634
post-steps] :as ctx}]
612-
(let [ctx (process-steps
635+
(let [default-steps
636+
(if-not (:exec-fn ctx)
637+
(concat
638+
start-steps
639+
before-steps
640+
pre-steps
641+
[start-clojure-process]
642+
post-steps
643+
after-steps
644+
end-steps)
645+
exec-fn-steps)
646+
ctx (process-steps
613647
(update ctx :aliases concat (map keyword (::cli/argv ctx)))
614-
(or steps
615-
(concat
616-
start-steps
617-
before-steps
618-
pre-steps
619-
[start-clojure-process]
620-
post-steps
621-
after-steps
622-
end-steps)))
648+
(or steps default-steps))
623649
processes (:processes ctx)]
624650
(System/exit (apply min (for [p processes]
625651
(.waitFor p))))))

0 commit comments

Comments
 (0)