clj [clj-opt*] [exec-opt]
clojure [clj-opt*] [exec-opt]
Clojure "endeavors to be a general-purpose language suitable in those areas where Java is suitable" (from Rationale). To effectively target the JVM platform, Clojure needs to provide ready access to Java libraries, ideally in a way suited for dynamic development. In practice, this means meeting the JVM platform in two places:
the classpath used when invoking JVM processes (and/or URLClassLoaders)
transitive dependency download and resolution from providers like Maven
Clojure build tools have traditionally taken the approach of wrapping the Maven ecosystem to gain access to Java libraries. However, they have also forced this approach on Clojure code as well, requiring a focus on artifacts that must be built and deployed (which Clojure does not require). This approach has created friction for Clojure developers, making it hard to e.g. work with libs not yet publishing artifacts, work on speculative changes w/o artifacts or across multiple libs, or give control to a 3rd party to manage shared dependencies.
To this end Clojure provides:
tools.deps.alpha - a library providing an API for resolving dependency graphs and building classpaths that can utilize both Maven and other providers of code or artifacts
Command line tools (clojure
and clj
) that enable users to make use of this capability at the terminal to declare dependencies, assemble classpaths, and launch Clojure programs with data
System-specific installers for downloading the tools, improving the "Getting Started" experience
You use the Clojure tools (clj
or clojure
) to run Clojure programs on the JVM, e.g. to start a REPL or invoke a specific function with data. The Clojure tools will configure the JVM process by defining a classpath (with desired libraries), an execution environment (JVM options), the main class, and args.
Using a deps.edn file (or files), you tell Clojure where your source code resides and what libraries you need. Clojure will then calculate the full set of required libraries and a classpath, caching expensive parts of this process for better performance.
The internal steps of the Clojure tools, as well as the Clojure functions you intend to run, are parameterized by data structures, often maps. Shell command lines are not optimized for passing nested data, so instead you will put the data structures in your deps edn file and refer to them on the command line via aliases - keywords that name data structures.
clj
and clojure
differ in that clj
has extra support for use as a REPL in a terminal, and should be preferred unless you don’t want that support, then use clojure
. The invocation structure is the same for both:
clj [clj-opt*] [exec-opt]
clojure [clj-opt*] [exec-opt]
Use the following exec-opt to invoke a function that takes a map:
clojure [clj-opt*] -X[aliases] [a/fn] [kpath v]*
-X
is configured with an arg map with :exec-fn
and :exec-args
keys, and stored under an alias in deps.edn
:
;; deps.edn
{:aliases
{:my-fn
{:exec-fn my.qualified/fn
:exec-args {:my {:data 123}
:config 456}}}}
To invoke, pass the name of the alias to -X
:
clj -X:my-fn
You can supply additional keys, or override values stored in the deps.edn file by passing pairs of key-path and value. The key-path should either be a single key or a vector of keys to refer to a nested key (as with assoc-in
). Each key-path will be used to assoc-in
to the original :exec-args
map, overriding the value there.
# Top key override
clj -X:my-fn :config 789
# Nested key override
clj -X:my-fn '[:my :data]' 789
See the later section on "Quoting keys and values" for more details on how to properly quote edn values on the command line. |
If you want to execute an arbitrary function, you can pass it on the command instead, along with pairs of key-path and value:
clj -X my.qualified/fn :config 789
Alias arg maps can also include a default namespace or namespace aliases for resolving the function (see "Namespace resolution" for more details). |
You can use the -M
exec-opt to invoke clojure.main, which supports calling a namespace with a -main
function or a Clojure script:
clojure [clj-opt*] -M[aliases] [main-opts]
The -M aliases are pulled from deps.edn
and combined to form an arg map. The arg map can modify the classpath or supply main options.
See the clojure.main documentation for more details on main options.
When you execute the Clojure tool, there are a series of steps performed to prepare and execute your command. This section is an overview of those steps, see later sections for how to modify those steps in a variety of ways.
Locate deps edn sources
Configuration is stored in one or more "deps edn" maps. These are edn maps with the following top-level keys:
:deps
- map of lib (symbol) to coordinate
:paths
- vector of paths
:aliases
- map of alias name to alias data
provider-specific keys for configuring dependency sources
The Clojure tools look for 4 potential deps edn sources:
Root - part of the clj installation (a resource in the tools.deps library)
User - cross-project configuration (typically tools), usually found at ~/.clojure/deps.edn
Project - the deps.edn
in the current directory
Config data - a deps edn map passed on the command line
Check cache
The next several steps of this execution can be skipped if we have already computed the classpath and cached it. Classpath and the runtime basis files are cached in the current directory under .cpcache/
. The key is based on the contents of the deps.edn files and some of the command arguments passed and several files will be cached, most importantly the classpath and runtime basis.
If the key is found, and the cached files are newer than all deps.edn sources, they will be used and execution begins immediately.
Replace project environment ("tool")
When you execute a tool in the context of your project, the tool can use its own paths and/or deps in place of the project’s paths and/or deps.
Merge sources
All deps edn sources are merged into a single master edn file in the order listed above - root, user, project (possibly with tool replacements), config. This merged deps will be included in the runtime basis and used after this point.
The merge is essentially merge-with merge
, except for the :paths
key, where only the last :paths
found is used (they replace, not combine).
Resolve dependencies
Starting from the master edn’s merged :deps, the full transitive expansion of the dependency tree is computed. Dependency sources (procurers) are used to obtain metadata and other dependency information. At the completion of this step, all libraries to use in the execution have been found and downloaded to local files if needed.
See dep expansion for more details on the dep expansion algorithm.
Make classpath
JVM execution relies on computing the classpath for the execution. The classpath will consist of the :paths
in the merged deps.edn
and the locations of all resolved dependencies.
Prepare JVM environment
JVM arguments may either be passed on the command line (with -J
) or by using data stored in an alias under :jvm-opts
and passed with -X
or -A
or -M
Execute command
Finally the command is executed - see the Overview above for the execution options. The already computed (or loaded from cache) classpath, JVM environment, and main arguments if relevant are used in the execution.
The configuration file format (in deps.edn
files) is an edn map with top-level keys :deps
, :paths
, and :aliases
, plus provider-specific keys for configuring dependency sources.
Paths are declared in a top level key :paths
and are a vector of string paths or alias names. Relative paths are resolved in relation to the directory containing the deps.edn (the project root). These source paths will be added to the classpath.
Example:
{:paths ["src"]}
If used, alias names should refer to a path vector in the alias data:
{:paths [:clj-paths :resource-paths]
:aliases
{:clj-paths ["src/clj" "src/cljc"]
:resource-paths ["resources"]}}
Dependencies are declared in deps.edn with a top level key :deps
- a map from library to coordinate. Libraries are symbols of the form <groupID>/<artifactId>
. To indicate a Maven classifier, use <groupId>/<artifactId>$<classifier>
.
Coordinates can take several forms depending on the coordinate type:
Maven coordinate: {:mvn/version "1.2.3"}
Other optional keys: :exclusions
Note: :classifier
is not supported - add to lib name as specified above
Local project coordinate: {:local/root "/path/to/project"}
Optional key :deps/manifest
Specifies the project manifest type
Default is to auto-detect the project type (currently either :deps
or :pom
)
Local jar coordinate: {:local/root "/path/to/file.jar"}
If the jar includes a pom.xml file, it will be used to find transitive deps
Git coordinate: {:git/url "https://github.com/user/project.git", :sha "sha", :tag "tag"}
Required key :git/url
can be one of the following:
https - secure anonymous access to public repos
ssh or user@host form urls (including GitHub) - ssh-based access (see Git configuration section)
Required key :sha
should indicate the full commit sha
Optional key :tag
is used only to indicate the semantics of the sha
Optional key :deps/root
Specifies the relative path within the root to search for the manifest file
Optional key :deps/manifest
- same as in :local
deps
{:deps
{org.clojure/tools.reader {:mvn/version "1.1.1"}
github-sally/awesome {:git/url "https://github.com/sally/awesome.git", :sha "123abcd549214b5cba04002b6875bdf59f9d88b6"}
;; ... add more here
}}
Aliases give a name to a data structure that can be used either by the Clojure tool itself or other consumers of deps.edn. They are defined in the :aliases
section of the config file. These Clojure tool subprocesses use data which can be read from aliases:
The core of the tools.deps library is a process to take a merged deps.edn file, arg maps for the resolve-deps and make-classpath steps, and produce the "runtime basis", or "basis" for short. The basis is a superset of the deps.edn file also containing those args, the lib map, and the classpath map.
The JVM classpath consists of a series of roots, either directory paths or the path to a jar file. Classes (and Clojure files) map via package or namespace to a path relative to a classpath root. For example, the java.lang.String
class can be found at path java/lang/String.class
and the clojure.set
Clojure namespace may be found at paths clojure/set.class
(for AOT), clojure/set.clj
, or clojure/set.cljc
. When the JVM needs to load one of these files it searches each root for the relative path and loads it when found.
We divide the process of building a classpath into two primary operations: resolve-deps
and make-classpath
.
(resolve-deps deps args-map)
resolve-deps
takes an initial map of required dependencies and a map of args that modify the resolution process. It builds a full graph of transitive dependencies, resolves any version differences, and flattens that graph to a full list of libraries to be included on the classpath.
The deps from the merged deps.edn is a map of library to coordinate. The library is (in Maven terms) the groupId and artifactId, which are sufficient to locate the desired project. The coordinate is used to describe a particular version that is being requested from a particular provider (like Maven or git).
For example, this deps map specifies a (Maven-based) dependency:
{org.clojure/core.cache {:mvn/version "0.6.5"}}
resolve-deps
expands these dependencies to include all transitive dependencies, cut cycles, resolve version differences, download required artifacts from the provider, and produce a lib map of the flattened set of all needed dependencies and where to find their artifacts:
{org.clojure/core.cache {:mvn/version "0.6.5",
:deps/manifest :mvn,
:paths [".../core.cache-0.6.5.jar"]}
org.clojure/data.priority-map {:mvn/version "0.0.7",
:deps/manifest :mvn,
:dependents [org.clojure/core.cache],
:paths [".../data.priority-map-0.0.7.jar"]}
... }
The lib map lists all libraries, their selected coordinates, the :paths
on disk, and a list of dependents that caused it to be included. Here you can see that data.priority-map
was included as a dependency of core.cache.
The second args-map
is a map of optional modifications to the standard expansion to account for common use cases: adding extra dependencies, overriding deps, and default deps. These can be used separately or together, or not at all:
{:extra-deps { ... }
:override-deps { ... }
:default-deps { ... }}
:extra-deps
is the most common modification - it allows you to optionally add extra dependencies to the base dependency set. The value is a map of library to coordinate:
{:extra-deps {criterium/criterium {:mvn/version "0.4.4"}}}
:override-deps
overrides the coordinate version chosen by the version resolution to force a particular version instead. This also takes a map of library to coordinate:
{:override-deps {org.clojure/clojure {:mvn/version "1.9.0"}}}
:default-deps
provides a set of default coordinate versions to use if no coordinate is specified. The default deps can be used across a set of shared projects to act as a dependency management system:
{:default-deps {org.clojure/core.cache {:mvn/version "0.6.4"}}}
(make-classpath lib-map paths args-map)
The make-classpath
step takes the lib map (the result of resolve-deps
), the internal source paths of the project ["src"]
, an args-map of optional modifications, and produces a classpath string for use in the JVM.
The args-map includes support for modifications to be applied while making the classpath: adding extra paths, and overriding the location of libraries specified in the lib map. These modifications can be used separately or together or not at all in a map like this:
{:extra-paths [ ... ]
:classpath-overrides { ... }}
:extra-paths
is used to include source paths in addition to your standard source paths, for example to include directories of test source:
{:extra-paths ["test" "resources"]}
:classpath-overrides
specify a location to pull a dependency that overrides the path found during dependency resolution, for example to replace a dependency with a local debug version. Many of these use cases are ones where you would be tempted to prepend the classpath to "override" something else.
{:classpath-overrides
{org.clojure/clojure "/my/clojure/target"}}
The Clojure tools will use the following deps.edn map sources, in this order:
Root - found in the installation of clj (or as a resource in tools.deps)
User - cross-project configuration (typically tools)
Locations used in this order:
If $CLJ_CONFIG
is set, then use $CLJ_CONFIG
(explicit override)
If $XDG_CONFIG_HOME
is set, then use $XDG_CONFIG_HOME/clojure
(Freedesktop conventions)
Else use $HOME/.clojure
(most common)
Project - the deps.edn
in the current directory
Config data - a deps.edn
map passed on the command line
The deps.edn sources can be modified or inspected by the following options:
-Sverbose
- print all source locations
-Sdeps
- pass the config data on the command line
-Srepro
- omit the user deps source (other sources will be used if found)
The cached classpath file is used for execution when:
It exists and
It is newer than all deps.edn
sources
Classpath and basis files are cached in a directory computed as follows:
If there is a project deps.edn
Use ./.cpcache
Else (no project deps.edn)
If $CLJ_CACHE
is set, then use $CLJ_CACHE
(explicit override)
If $XDG_CACHE_HOME
is set, then use $XDG_CACHE_HOME/clojure
(Freedesktop conventions)
Else use config_dir/.cpcache
(see deps.edn sources for config_dir logic, usually ~/.clojure
)
A hash is computed based on the config file paths, the resolve-aliases, and the classpath aliases.
Files cached (if needed):
<hash>.libs
- a ::lib-map
in the specs, the output of running resolve-deps
<hash>.cp
- a classpath string, the output of make-classpath
<hash>.jvm
- jvm options for main execution
<hash>.main
- main options for main execution
<hash>.basis
- the runtime basis, passed to the program
Caching can be modified by the following options:
-Sforce
- ignore cache and force recomputation
-Scp CP
- don’t use cache or compute, use the provided classpath instead
The tool
process is used when executing a tool that should not use the project classpath environment. This process takes the project deps.edn and the following modifier args and replaces them (if provided) before the project deps is merged:
:replace-deps
- a deps map from lib to coordinate of deps to REPLACE the project :deps
:replace-paths
a collection of string paths to REPLACE project :paths
This tool map should be provided as an alias in one of the deps sources and provided to the Clojure tools using -A (for REPL invocation), -X (for function execution), or -M (for clojure.main execution). Multiple aliases can be provided by concatentating the alias names.
The deps.edn
files found from the source locations (with Clojure tool modifications by any options) are merged to form one master deps map. The merge is done in the order above root/user/project/config, last one wins. The operation is essentially merge-with merge
, except for the :paths
key, where only the last one found is used (they are not combined).
The resolve-deps modifiers are provided in a map that was described in a prior section:
:extra-deps
- a deps map from lib to coordinate of deps to add to the deps
:override-deps
- a deps map from lib to coordinate of override versions to use
:default-deps
- a deps map from lib to coordinate of versions to use if none is found
If multiple alias maps with these keys are activated, all of them are merge-with merged
The resolve-deps args should be provided as an alias in one of the deps sources and provided to the Clojure tools using -A (for REPL invocation), -X (for function execution), or -M (for clojure.main execution). Multiple aliases can be provided by concatentating the alias names.
The make-classpath modifiers are provided in a map that was described in a prior section:
:extra-paths
- a collection of string paths to add to :paths
:classpath-overrides
- a map of lib to string path to replace the location of the lib
If multiple maps with these keys are activated, :extra-paths
concatenate and :classpath-overrides
merge-with merge
The resolve-deps args should be provided as an alias in one of deps sources and provided to the Clojure tools using -A (for REPL invocation), -X (for function execution), or -M (for clojure.main execution). Multiple aliases can be provided by concatentating the alias names.
The JVM has many options and some programs also take configuration via Java system properties. JVM options can be passed on the command line for any execution specfier by prefixing with -J
. If multiple options are specified, each must be prefixed.
Additionally, main execution can take a map with key :jvm-opts
:
:jvm-opts
- a collection of string JVM options
If multiple maps with these keys are activated, :jvm-opts
concatenate
If -J JVM options are also specified on the command line, they are concatenated after the alias options
This map is stored in alias data and provided to the Clojure tools using -A (for REPL invocation), -X (for function execution), or -M (for clojure.main execution). Multiple aliases can be provided by concatentating the alias names.
One additional option for main execution is a map with key :main-opts
:
:main-opts
- a collection of clojure.main options
If multiple maps with these keys are activated, only the last one will be used
If command line clojure.main arguments are supplied on the command line, they are concatenated after the last main alias map
This map is stored in alias data and provided to the Clojure tools using -M:an-alias
. Multiple aliases can be provided by concatentating the alias names.
The -P
flag can be used with any other execution mode to "prepare" but not execute. Importantly, this flag will cause the Clojure tool to resolve deps, download libraries, make and cache classpaths. This may be useful in containers, continuous integration systems, etc where an environment can be prepared to execute and do necessary network activity first, and then later execute without that activity.
There are some options that can be provided to clj
that short circuit normal execution and run an alternate program instead:
-Sdescribe
- print environment and command parsing info as data
-Spath
- compute classpath and echo to stdout only
The :deps
alias is built into the root deps.edn and provides a default namespace with several additional programs:
-X:deps tree
- print dependency tree (also see tree printing)
-X:deps mvn-pom
- generate (or update an existing) pom.xml with deps and paths
-X:deps git-resolve-tags
- resolve git coordinate tags to shas and update deps.edn
The -X:deps mvn-install
program is provided with the Clojure tools for convenience and can be executed with -X
to install a jar into your local Maven cache.
The install argmap takes the following options:
Required:
:jar - path to jar file, use pom inside jar by default
To supply an explicit pom file:
:pom - path to pom file (used instead of pom inside the jar)
To generate a minimal pom file:
:lib - qualified symbol like my.org/lib
:version - string
:classifier - string
Other options:
:local-repo - path to local repo (default = ~/.m2/repository)
You can pass overrides on the command line for these as needed:
clj -X:deps mvn-install :jar '"/path/to.jar"'
As mentioned above, edn strings must be in double quotes, and then single-quoted for the shell.
A pom file must be either provided explicitly, generated from :lib/:version, or found inside the .jar file (the default).
Coordinates are interpreted by procurers, which know how to determine dependencies for a library and download artifacts. tools.deps.alpha is designed to support an extensible set of procurers that can expand over time. Currently the available procurers are: mvn
, local
, and git
.
The procurer to use is determined by examining the attributes of the coordinate and using the first attribute qualifier that’s found (ignoring the reserved qualifier "deps"). For example, a Maven coordinate contains a :mvn/version
attribute and a local coordinate contains a :local/root
attribute.
Procurers may also have configuration attributes stored at the root of the configuration map under the same qualifier.
The mvn
procurer will look for :mvn/repos
. The installation deps.edn configures the default Maven repos:
{:mvn/repos
{"central" {:url "https://repo1.maven.org/maven2/"}
"clojars" {:url "https://clojars.org/repo"}}}
The :mvn/repos
map is merge-with
merge
across the deps.edn sources, so you can modify the default repositories by specifying a new definition or remove it by specifying nil
.
tools.deps guarantees that the "central"
and "clojars"
repositories will be checked first for Maven libraries.
For Maven deps in authenticated repositories, existing Maven infrastructure is used to convey credentials.
In your ~/.m2/settings.xml
:
<settings>
...
<servers>
<server>
<id>my-auth-repo</id>
<username>zango</username>
<password>123</password>
</server>
...
</servers>
...
</settings>
Then in your deps.edn
include a repo with a name matching the server id (here my-auth-repo
):
{:deps
{authenticated/dep {:mvn/version "1.2.3"}}
:mvn/repos
{"my-auth-repo" {:url "https://my.auth.com/repo"}}}
Then just refer to your dependencies as usual in the :deps
.
The tools also provide support for connecting to public and private S3 Maven repositories.
Add a :mvn/repos
that includes the s3 repository root:
{:deps
{my/library {:mvn/version "0.1.2"}}
:mvn/repos
{"my-private-repo" {:url "s3://my-bucket/maven/releases"}}}
S3 buckets are specific to the AWS region they were created in. The s3 transporter will attempt to determine the bucket’s location. If that doesn’t work, you can specify the bucket region in the url explicitly: "s3://my-bucket/maven/releases?region=us-west-2"
.
For authenticated repos, AWS credentials can be set in the ~/.m2/settings.xml
on a per-server basis or will be loaded ambiently from the AWS credential chain (env vars, etc). The repository name in deps.edn
must match the server id in settings.xml
:
<settings>
...
<servers>
<server>
<id>my-private-repo</id>
<username>AWS_ACCESS_KEY_HERE</username>
<password>AWS_SECRET_ACCESS_KEY_HERE</password>
</server>
...
</servers>
...
</settings>
AWS S3 credentials can be set in the environment using one of these mechanisms:
Set the environment variables AWS_ACCESS_KEY_ID
and AWS_SECRET_ACCESS_KEY
.
Create a default profile in the AWS credentials file ~/.aws/credentials
(older ~/.aws/config
also supported).
Create a named profile in the AWS credentials file and set the environment variable AWS_PROFILE
with its name.
Amazon ECS container and instance profile credentials should also work, but have not been tested.
For more information, most of the advice in this AWS document describes how credentials are located. Note however that the Java system properties options will NOT work with the command line tools (but would work if using the tools.deps.alpha library directly).
In environments where the internet is accessed via a proxy, existing Maven configuration in ~/.m2/settings.xml
is used to set up the proxy connection:
<settings>
...
<proxies>
<proxy>
<id>my-proxy</id>
<host>proxy.my.org</host>
<port>3128</port>
<nonProxyHosts>localhost|*.my.org</nonProxyHosts>
</proxy>
</proxies>
...
</settings>
Refer to the Maven Guide to using proxies for further details.
For adding custom headers to outgoing HTTP requests, existing Maven configuration in ~/.m2/settings.xml
is used.
<settings>
...
<servers>
<server>
<id>my-token-repo</id>
<configuration>
<httpHeaders>
<property>
<name>Private-Token</name>
<value>abc123</value>
</property>
</httpHeaders>
</configuration>
</server>
...
</servers>
...
</settings>
The server id in settings.xml
must match the repository name in deps.edn
:
{:mvn/repos
{"my-token-repo" {:url "https://my.auth.com/repo"}}}
This mechanism is used by repositories that authenticate using a token, rather than by username and password.
The supported git url protocols are https and ssh. https repos will be accessed anonymously and require no additional authentication information. This approach is recommended for public repos.
ssh repos may be either public or private. Access to a git repo via ssh requires an ssh keypair. The private key of this keypair may or may not have a passphrase. ssh authentication works by connecting to the local ssh agent (ssh-agent on *nix or Pageant via PuTTY on Windows). The ssh-agent must have a registered identity for the key being used to access the Git repository. To check whether you have registered identities, use:
$ ssh-add -l
2048 SHA256:S2SMY1YRTRFg3sqsMy1eTve4ag78XEzhbzzdVxZroDk /Users/me/.ssh/id_rsa (RSA)
which should return one or more registered identities, typically the one at ~/.ssh/id_rsa
.
For more information on creating keys and using the ssh-agent to manage your ssh identities, GitHub provides excellent info:
Note: user/password authentication is not supported for any protocol.
Cloned git dirs and working trees are stored by default in ~/.gitlibs
. This directory is a cache and can be safely removed if needed. The cache location can also be overridden with the environment variable $GITLIBS.
For tools installation, see the instructions in the Getting Started guide.
This section summarizes all of the available arg map keys that clj
uses and that can be conveyed via alias data in deps.edn. For clarity, these are separated by category, but in general, all of them can be used with -X
(exec), -A
(repl), and -M
(main).
tool
:replace-deps
- map of lib to coords that should replace the project deps
:replace-paths
- vector of path strings that should replace the project paths
resolve-deps
:extra-deps
- map of lib to coords that should be added to the root deps
:override-deps
- map of lib to coords that should replace deps in the root deps
:default-deps
- map of lib to coords that should be used if the coord is nil in root or transitive deps
make-classpath
:extra-paths
- vector of string paths (or keyword aliases to same) to add to base paths
:classpath-overrides
- map of lib to string path to replace lib on classpath
jvm opts
:jvm-opts
- vector of strings to pass as jvm args
namespace aliasing
:ns-aliases
- map of alias symbol to namespace symbol, used to resolve symbols (such as :exec-fn)
:ns-default
- default namespace for unqualified symbols (such as :exec-fn)
execution (-X only)
:exec-fn
- function to execute with -X
:exec-args
- function args to pass to -X (can be overridden at command line)
main (-M only)
:main-opts
- vector of string args to pass to clojure.main
Symbols in the exec-opts or argmaps (like :exec-fn
) are resolved with the following rules:
If function is unqualified, use the namespace in the :ns-default
key in the arg map (if none, this is an error)
If function is qualified, and the qualifier is an alias in the arg map under :ns-aliases
, use that namespace
Else use the fully qualified function symbol
With the -X exec-opt you can supply key-path/value pairs on the command line. The key-path is either a single key or a vector of keys to refer to a nested key (as with assoc-in
). Each key-path will be used to assoc-in
to the original :exec-args
map, overriding the value there.
# Top key override
clj -X:my-fn :val 789
# Nested key override
clj -X:my-fn '[:my :data]' 789
Keys and values on the command line are read as edn. The following data can be used without quoting:
Numbers - 123
, 12.4
Booleans - true
, false
Nil - nil
Symbols - name
, foo/bar
Keywords - :id
, :company/name
These data types need to be surrounded by single quotes:
Strings - '"hi there"'
- note use of both single quotes for the shell and double quotes to be read as an edn string
Vectors - '[1 2 3]'
Maps - '{:a 1, :b 2}'
Sets - '#{:a :b}'
Lists - '(1 2 3)'
Library
An independently-developed chunk of code residing in a directory hierarchy under a root. We will narrow to those libraries that can be globally named, e.g. my.namespace/my-lib
.
Artifact
A snapshot of a library, captured at a point in time, possibly subjected to some build process, labeled with a version, containing some manifest documenting its dependencies, and packaged in e.g. a jar.
Coordinate
A particular version of a library chosen for use, with information sufficient to obtain and use the library.
Dependency
An expression, at the project/library level, that the declaring library needs the declared library in order to provide some of its functions. Must at least specify library name, might also specify version and other attrs. Actual (functional) dependencies are more fine-grained.
Dependency types:
maven artifacts
unversioned libraries - a file location identifying a jar or directory root
git coordinates
Classpath (and roots/paths)
An ordered list of local 'places' (filesystem directories and/or jars) that will form root paths for searches of requires/imports at runtime, supplied as an argument to Java which controls the semantics. We discourage order-dependence in the classpath, which implies something is duplicated (and thus likely broken).
Expansion
Given a set of root dependencies, a full walk of the transitive dependencies.
Resolution
Given a collection of root dependencies and additional modifications, creates a fully-expanded dependency tree, then produces a mapping from each library mentioned to a single version to be used that would satisfy all dependents, as well as the local path. We will also include those dependents for each entry. Conflicts arise only if libraries depend on different major versions of a library.
Classpath creation
Creates a classpath from a resolved lib-map and optional extra local lib paths. Current plan for lib-map does not provide for control over resulting order.
Version
A human numbering system whose interpretation is determined by convention. Usually x.y.z. Must protect against 'semver' interpretation, which allows libraries to break users while keeping the name the same. Ascending by convention - higher numbers are 'later', vague compatibility with lower/earlier.
Version difference
This occurs when the dependency expansion contains the same library with more than one "version" specified but where there is a relative ordering (either by number or by SHA etc). Version differences can be resolved by choosing the "later" or "newest" version when that relationship can be established.
Version conflict
A version conflict occurs when the dependency expansion contains the same library with more than one "version" such that the best choice cannot be automatically chosen:
semver version breakage (major version changed)
github shas that do not contain any common root or ancestry (two shas on different branches or unrelated repos, for example)
versions that cross different repos or repo types such that no relative relationship can be established
Maven Repo
A repository of library artifacts - e.g. Maven central or Clojars
Requires and imports
Mentions in source code of library (sub)components that must be in the classpath in order to succeed. namespace and package/class names are transformed into path components.
See the project’s wiki for a list of tools that use or work with tools.deps.alpha (or the clojure tools) - tools for project creation, packaging, and much more.