Hey Ari, welcome!
One thing to understand is that tools.deps and the Clojure CLI are not build tools.
tools.deps is a dependency manager and classpath generator. While Clojure CLI is a command line launcher for Clojure app which uses tools.deps to pull in dependencies and generate the required app classpath.
More simply speaking, you write some Clojure;
hello_world.clj
(ns hello-world)
(defn -main [& _]
(println "Hello World"))
Now you want to run it? Not so easy. You would need to do the following:
- Manually download the Clojure Jar and save it next to your hello_world.clj file
- Manually download the Clojure spec Jar and save it next to your hello_world.clj
- Manually download the Clojure core spec Jar and save it next to your hello_world.clj
- Use java, the clojure, spec and core spec Jars in combination to run your code:
java -cp .:./clojure-1.10.1.jar:./spec.alpha-0.2.176.jar:./core.specs.alpha-0.2.44.jar clojure.main -m hello-world
We don’t want to do all that. So the core team has released two tools to make this easier: tools.deps and Clojure CLI.
With the Clojure CLI, we can do:
clj -Scp .:./clojure-1.10.1.jar:./spec.alpha-0.2.176.jar:./core.specs.alpha-0.2.44.jar -m hello-world
That’s not really better then when straight up using java. We only avoid having to call to clojure.main specifically, but we still need to download all Jars ourselves and put together the path to all of them and our code manually.
Luckily for us, it comes bundled with tools.deps. So now instead of manually downloading the three Jars and putting the classpath together ourselves we can simply create a file called deps.edn where we just declare the dependencies we want, and let the Clojure CLI download them for us, save them in a folder locally, and create the classpath to them:
deps.edn
{:paths ["."]
:deps {org.clojure/clojure {:mvn/version "1.10.1"}}}
And now we can run it by simply doing:
clj -m hello-world
:paths
is the path to our code we want added to the classpath, and :deps
is the list of dependencies we want tools.deps to automatically download and add to our classpath for us.
So the steps become:
- Create a deps.edn file and specify the path to your code and the depencies it needs to run.
- Run
clj -m your-main-namespace
That’s it! This is literally the only point of the Clojure CLI and tools.deps. To download the dependencies needed by a Clojure application, create the classpath to them, and launch the application.
You can create named groups of dependency sets and main namespaces called Alias as a convenience, and so you can then use the same deps.edn file to launch different Clojure app, by specifying which alias to run. Or launch the same Clojure app but with different settings, dependencies, entry point, etc.
Now Leiningen and Boot were tools which could also do all this, though using a slightly different mechanism.
What the Clojure CLI and tools.deps is not though, is everything else Leiningen and Boot can do, that is, it is not a build tool.
What does a build tool do? Well, it can run arbitrary tasks and create arbitrary chains of them. Normally, you use them to say compile your code ahead of time. Package your code as a library Jar, or full app Uberjar. Run a linter over your code. Run a test runner to check your tests against your code. Etc.
What the hell is a “task” though? In the abstract, that’s any piece of code. But to a build tool, a “task” is a way to bundle some arbitrary piece of code so that the build tool can execute it, give it some context, read its result, pass that result to the next task, etc.
Now when you think about it, the operating system already has exactly that, its called a process, and you can pipe input and output between them, and chain them. So what Clojure CLI and tools.deps do, is that if you build your “tasks” as Clojure programs, each task is a program which possibly takes input and returns output. And since Clojure CLI is a launcher for Clojure programs, well you got yourself a build tool! How cool is that!
Now Lein and Boot come with a bunch of useful common build related tasks, and Clojure CLI + tools.deps does not. But the community has started building tasks for it, which remember, are just normal Clojure apps.
Here’s a good list of them: https://github.com/clojure/tools.deps.alpha/wiki/Tools
The trick is you just create an alias for each one that you want, such as what @seancorfield does here: https://github.com/seancorfield/dot-clojure/blob/master/deps.edn
The only thing is that tools.deps and the Clojure CLI don’t allow a way to chain things together. So for now, you can only run one task at a time. So if you want to run multiple tasks. Like you can’t create a task of tasks. Also each one runs inside its own JVM, so they take longer to start, if you need to do a few of them back to back.
Regards!