Common alias definitionsλ︎
Task: Run a simple terminal REPLλ︎
clojure
and clj
(requires rlwrap) will run a REPL if given no other arguments.
Running either command from the root directory of a project will merge the deps.edn
configuration with ~/.clojure/deps.edn
.
Task: Run a REPL with additional dependencies and pathsλ︎
clojure -M:alias
will run a repl if the alias does not contain a main namespace defined in :main-opts
, e.g. :main-opts ["-m" "namespace.main"]
. The deps and path values are included from the alias.
If the following alias is defined in the project deps.edn
file
clojure -M:env/dev
will add resources
directory to the path and the h2 database library to the dependencies, then runs a REPL.
Including the -r
option in the command line forces a REPL to run, even if a main namespace is provided via :main-opts
or the command line.
The dependencies and paths will be merged from the alias from left to right, with each successive alias over-riding the value of any matching keys in the dependencies.
Task: Create a new project from templateλ︎
The clj-new
community tool can be used to create a Clojure / ClojureScript project, using a template to provide a project structure and example source code and tests.
Using the :main-opts
approach, an alias for clj-new
would be defined as follows
:project/new
{:extra-deps {seancorfield/clj-new {:mvn/version "1.0.215"}}
:main-opts ["-m" "clj-new.create"]}
The clj-new
tool can be run using the -M
flag, passing the template and project names as arguments.
clojure -M:project/new template-name project-domain/application-name
To create a project as an application (to be run via the command line) for the practicalli domain with the application called banking-on-clojure
The latest version of the clj-new
project also supports using the -X
flag and default arguments.
Adding the :exec-fn
to the clj-new
alias, the -X
flag can be used instead of the -M
. Arguments are supplied as key/value pairs
Use this alias with the -X
flag
Default values can be added using the :exec-args
key to the alias
:project/new
{:extra-deps {seancorfield/clj-new {:mvn/version "1.1.215"}}
:exec-fn clj-new.create
:exec-args {:template lib :name practicalli/playground}}
clojure -M:project/new :name practicalli/awesome-webapp
will create a new project using the {:template lib :name practicalli/awesome-webapp}
argument.
Task: Executing a specific functionλ︎
Clojure can run a specific function, useful for one off tasks or timed batch processing (via cron or similar tool) as well as complete applications.
Arguments to the function are passed as a hash-map, defined in either an aliases :exec-args
key or as key value pairs on the command line. Command line key value pairs are merged with the :exec-arg
hash-map, replacing the values from the command line if there are matching keys.
Scenarios
clojure -X namespace/fn
runs the function specified on the command line, passing an empty hash-map as an argument
clojure -X:alias fn
runs the function if the :ns-default
is set to the namespace that contains the function, otherwise "Unqualified function can't be resolved: fn-name" error is returned.
clojure -X:alias
runs the function specified by :exec-fn
in the alias. The function must include its namespace or have that namespace defined in :ns-default
. If :exec-args
is defined in the alias, its value is passed to the function, otherwise an empty hash-map is passed to the function as an argument.
clojure -X:alias namespace/fn
will run the function specified on the command line, over-riding :exec-fn
if it is defined in the alias. :exec-args
will be passed to the command line function if defined in the alias. Dependencies and paths will be used from the alias. Assumption: the command line namespace also overrides the :ns-default
value if set.
clojure -X:alias :key1 val1 :key2 val2
will execute the function defined in :exec-fn
and pass it the key value pairs from the command line as a hash map. If the alias has :exec-args
defined, command line args are merged into the :exec-fn
hash-map, replacing the default values in :exec-args
where keys match.
Assuming there is an alias called database/migrate
defined in the project deps.edn
:database/migrate
{:exec-fn practicalli.banking-on-clojure.database/migrate
:exec-args {:db-type "h2" :database "banking-on-clojure"}}
clojure -X:database/migrate :database "specs-repository"
would merge the command line args with :exec-args
to create the hash-map {:db-type "h2" :database "specs-repository"}
which is passed to the practicalli.banking-on-clojure.database/migrate
function as an argument.
Task: Executing a range of functionsλ︎
:ns-default
in an alias defines the namespace that contains the functions that could be executed.
Specific functions from the namespace can be called via the command line
clojure -X:project/run migrate-db :db-type h2 :database banking-on-clojure
clojure -X:project/run server-start :port 8080
Task: Dry Run or Prepare for CI / Containersλ︎
clojure -P
will download the libraries defined in :deps
in the project deps.edn
and do nothing else. Standard out shows downloading of dependencies not already cached locally, including name and versions and repository downloaded from.
Qualified namespaces required
If an unqualified library name is used, e.g. compojure
, then a warning is sent to the standard out. Change the name of the library to be fully qualified e.g. weavejester/compojure
. Use the same name if there is no official qualified domain, e.g. http-kit/http-kit
The -P
flag can be used to modify an existing command to ensure no execution takes place, ensuring a prepare only (dry run) action.
clojure -P -M:alias-name
downloads the dependencies for the specific aliases and multiple aliases can be chained together, e.g. clojure -P -M:dev/env:test-runner/kaocha
The -P
flag uses everything from an alias not related to execution.
The classic way to download deps was to run
clojure -A:aliases -Spath
, where-Spath
prevented execution of repl or main.
Run a Clojure applicationλ︎
clojure -m full.namespace.to.dash-main
calls the -main
function from the given namespace. Arguments to the function are simply added to the end of the command line and passed to the -main
function in the given namespace.
The
-m
flag in the CLI tools pre-release returns a warning that-M
should be used.
Using -M
and -m
works, but seems redundant. Using -M
by itself runs the REPL.
-M
seems useful when including an alias with extra configuration (eg. :extra-deps
, :extra-paths
, :main-opts
). As :main-opts
is no different to the -m
option, creating an alias just to avoid the warning seems excessive.
Task: Executing a project - using Edn style argsλ︎
Clojure CLI tools is encouraging a move to functions that take a hash-map for their arguments. Passing arguments in as an edn data structure has more rigor than options and strings on the command line.
The simplest form is to define an alias to run the project, specifying just the function to execute using :exec-fn
Then the project can be run using this alias.
Arguments can be passed to the function as key/value pairs on the command line.
:exec-args
provides a way to define default arguments for the function, regardless of if it is defined in ;:exec-fn
or passed via the command line.
:exec-args
defines a hash-map of arguments so the function must support taking a hash-map as an argument.
A function may take variable args, especially if it is supporting both hash-maps and strings as options.
:aliases
{:project/run
{:exec-fn fully.qualified/namespace
:exec-args {:default "arguments" :can-be-over-ridden-by "command-line-args"} }
} ;; End of Aliases
Adding :exec-args
to the :run-project
:aliases
{:project/run
{:exec-fn practicalli.banking-on-clojure/server-start
:exec-args {:port 8888 :host "localhost"}}
} ;; End of Aliases
Example of running a Clojure project - hello-worldλ︎
In this example I use the hello-world example from https://clojure.org/guides/deps_and_cli#_writing_a_program
A project deps.edn
file was created containing the dependency for clojure.java-time and the source code from that page copied into src/hello.clj
clojure -m
hello runs the project and returns the time from running the -main function.
However this gives a warning:
clojure -M
runs a REPL
clojure -M -m hello
runs the project and returns the time. But then I ask myself what is the purpose of -M
Creating an alias to run the project seems an interesting idea, as I could also set default arguments.
Adding an :project-run
alias to the project deps.edn
works when calling with clojure -M:project-run
Changing the :project-run
alias to use :exec-fn
and a fully qualified function (-main by default) should work when calling with clojure -X:project-run
.
:aliases
{:run-project {:exec-fn hello]}}
However, the hello-world
project has an unqualified function and cannot be resolved.
Moving the source code to src/practicalli/hello.clj
and calling clojure -X:run-project
gives an execution error, (ArityException)
as the -main
function does not take any arguments, (defn -main [] ,,,)
.
Changing the -main
function to (defn -main [& args] ,,,)
fixes the arity exception and calling clojure -X:run-project
works.
Local Maven installλ︎
Install a jar into the local Maven cache, typically ~/.m2/repository/
directory, organised by groupId
edn strings must be in double quotes, and then single-quoted for the shell
mvn-install
uses the .pom
file contained in the jar (if it exists) to determine the groupId, artifactId, and version coordinates to use when the jar is installed.
The .pom
file can also be specified using the :pom
argument.
The install argmap takes the following options:
key | Required | Description |
---|---|---|
:jar |
required | path to the jar file to install |
:pom |
optional | path to .pom file (if .jar file does not contain .pom) |
:lib |
optional | qualified symbol e.g my.org/lib |
:version |
optional | Version number of library (string type) |
:classifier |
optional | (string type) |
:local-repo |
optional | path to local repo (default = ~/.m2/repository) |