Should I use boot or tools.deps to build command line applications?


#21

I messed with this about a year ago. It runs clj twice, so it’s not ideal, but I like the way it looks.

Cheers,
Devin


#22

I’ve been tweaking my implementation. Here it is!

It now includes arguments, a place for other options, and it doesn’t depend on bash. I’ve included it below, but you can also find the most recent version in this gist.

#!/bin/sh
#_(

   #_DEPS is same format as deps.edn. Multiline is okay.
   DEPS='
   {:deps {clj-time {:mvn/version "0.14.2"}}}
   '

   #_You can put other options here
   OPTS='
   -J-Xms256m -J-Xmx256m -J-client
   '

exec clojure $OPTS -Sdeps "$DEPS" "$0" "[email protected]"

)

(println "Hello!")

(require '[clj-time.core :as t])

(prn (str (t/now)))

(prn *command-line-args*)

(println (.. (Runtime/getRuntime)
             totalMemory))


#23

I’m using both boot and clj for command line scripts and I’ve also done some Haskell: I must say it’s a great fit for this.

This is a standalone script using clj: https://github.com/borkdude/balcony/blob/master/balcony.clj. It uses a trick comparable to @ericnormand’s script above to include the deps configuration.

I later decided to port it to Haskell for fun but then it turned into more than one file. I’m still running that on my server: https://github.com/borkdude/balcony-hs.

Here’s an example of a standalone boot script that you can call with e.g. ./foobar -t:

#!/usr/bin/env boot

(set-env! :dependencies '[[clj-time "0.14.2"]])
(require '[clj-time.core :as time])

(deftask my-task [t time bool "Show time"]
  (when (:time *opts*)
    (println (time/now))))

(defn -main [& args]
  (apply boot "my-task" args))

If you already have boot installed and you want a single file standalone script, I’d say boot works well without crazy shell hacks. The startup time of clj might be a little better due to classpath caching. Lastly, Haskell probably has much better start times for scripts :slight_smile:.


#24

That is a piece of art.


#25

I wonder if @alexmiller has a plan to add “in-script” deps.edn support to tools.deps?


#26

Also, to the people suggesting Haskel for scripts, how do you bring in the dependencies if you need any?


#27

https://docs.haskellstack.org/en/stable/GUIDE/#script-interpreter


#28

My take on self-containing scripts: https://gitlab.com/eval/cljscript/blob/1d7d99723804536e6705bc808a613c7e34445dea/libexec/cljscript

It allows for scripts like:

#!/usr/bin/env cljscript
"DEPS='clj-time=RELEASE;some-other=1.2.3'"

(require '[clj-time.core :as t])

(defn -main [& args]
  (println (t/now)))

-main is invoked when present.


#29

The new incarnation of this script is ohmyclj.
It adds a repl and an easy way to run tests in the script.