Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use -M, -A or -X with Clojure CLI?

Tags:

clojure

I was always using -A with clojure tools, but some warnings were saying that I should use -M instead, I found this doc, but haven't got to a conclusion when to use each yet.

like image 261
Jp_ Avatar asked Apr 02 '21 22:04

Jp_


1 Answers

The Clojure CLI is still evolving so, the -X option is relatively new, and the meaning of the -M option has changed in the same timeframe.

You can see the CLI versions and short release notes here: https://clojure.org/releases/tools

Up until the middle of 2020, you used -A for everything. -M simply ran the :main-opts -- it did not respect any classpath options or resolving options.

In version 1.10.1.697 (September 25, 2020), the -X option was introduced to allow for execution of a specific Clojure function, passing a hash map of data as the single argument. That release also expanded the behavior of the -M option to respect :extra-paths and :extra-deps as well as running :main-opts -- effectively making -M equivalent to -A.

There were quite a few changes to how those options worked and how the CLI overall behaved, until things settled down about a month later with 1.10.1.727 (October 21, 2020). During this time, the -A option's behavior of running :main-opts was effectively deprecated: if you use -A to run :main-opts now, you'll get a warning that you should use -M instead.

Several community tools based on the Clojure CLI and deps.edn have notes in their README that you need to use at least version 1.10.1.727 in order to leverage their features. Version 1.10.3.814 is the current version (as of March 16, 2021). It's worth staying up to date as the CLI adds new features (and it's likely to get another round of changes soon).

The TL;DR of all this is:

  • Use -M to run clojure.main and any :main-opts -- this includes -m to identify a namespace whose -main function should be executed and also -e to evaluate an expression. Note that -main is a variadic function that is invoked with zero or more String arguments.
  • Use -X to run a specific function, taking a single hash map as its argument, passing in key/value pairs via the command-line, in addition to the :exec-args in deps.edn. Note that -X accepts EDN values, which means that strings need to be quoted carefully on the command-line: '"A string"' -- the double-quotes are for EDN strings and the single-quotes are to ensure the value is passed as-is via the shell. On Windows, via cmd.exe or Powershell, quoting is more complex than this (it is much easier to use the Clojure CLI on Linux and macOS, so for Windows it is worth considering WSL2).
  • Use -A to start a REPL. For now, that means you need to be careful about mixing :main-opts with aliases that you use when starting a REPL (because -A still runs :main-opts but at some point it will stop doing that).

Another useful option these days is -P -- prepare -- which you can add immediately after clojure (before -X, -M, or -A), which lets the CLI calculate and resolve all of the dependencies from the deps.edn files and the provided aliases (and download Maven/Clojars JARs and clone git deps), but then stops prior to actual execution of a function (the specific function for -X, clojure.main for -M, or the REPL for -A).

A final note on versions: although the CLI version number is prefixed with a Clojure version number, they are not directly tied. You can run any version of Clojure (back to 1.0.0) with any version of the CLI. The version number for the CLI is x.y.z.commits where x.y.z is the default version of Clojure you will get if you don't override it via an alias or via your project's deps.edn file.

like image 194
Sean Corfield Avatar answered Sep 23 '22 21:09

Sean Corfield