A clojure.tool that allows to work with projects in a streamlined way.
It provides an api for common project management tasks, inspired by
the conventions enforced by leiningen
Add this to your deps.edn
:project {:deps {io.github.exoscale/tools.project {:git/sha "..."}}
:ns-default exoscale.tools.project}Or install the tool locally:
clojure -Ttools install io.github.exoscale/tools.project '{:git/sha "..."}' :as projectWith the tool installed, a new project can be initialized with:
clojure -Tproject init :name com.example/my-libOnce installed, tools can called using standard tool call syntax, within the project directory:
clojure -T:project jar
clojure -T:project uberjarA convenience Makefile is provided with projects bootstrapped with
clojure -Tproject init, which can assist in discovering the tool.
- add-module: creates a new submodule
- check: validates that namespaces can be loaded
- clean: cleans target directories
- deploy: deploys jars to remote repositories
- format-check: source code format check
- format-fix: source code format fixing
- init: initialize new project
- install: local maven installation
- jar: JAR and POM generation
- lint: source code linting
- merge-deps: managed dependency management
- merge-aliases: managed alias management
- outdated: outdated version check
- prep: handle prep libs
- prep-self: handle prep task for the current project
- release: project release
- task: arbitrary task run
- test: run tests
- uberjar: standalone JAR generation
Note that tools.project does not provide a repl task, this is due to the
fact that deps.edn files are always fully function when using this tool, the
standard clj tool can be used to start a REPL, editor integration will also
remain fully functional.
A few keys control the configuration of the project. A minimum configuration is shown below:
{:exoscale.project/lib com.example/my-lib
:exoscale.project/version-file "VERSION"
:exoscale.project/uberjar? true
:paths ["src" "resources"]
:deps {org.clojure/clojure {:mvn/version "1.11.1"}}}See configuration options for a list of all valid options.
Some projects need to build several artifacts, or to expose different libraries. This is what we refer to as multi-module projects.
tools.project supports multi-module projects out of the box, and provides the following functionality:
- All targets adopt a default behavior that is dependent on whether they are called for a multi-module, or standalone project.
- Submodules of a project must be transparent to tooling, i.e: each submodule of
a project should have its own fully functional
deps.ednfile, requiring no additional tooling. - Default facilities are present to share dependencies and aliases across modules (through deps-modules.
Under the cover, deps-modules uses a mechanism to allow dependency expressions to inherit dependencies from the parent module. To ensure that submodules remain fully independent, deps files are rewritten (see merge-deps and merge-aliases for details.
Let's assume the following module structure:
superproject
├── deps.edn ;; com.example/superproject-common
└── modules
├── client
│ └── deps.edn ;; com.example/superproject-client
└── server
└── deps.edn ;; com.example/superproject-server
The corresponding top-level deps.edn file would
add the following:
{:exoscale.project/lib com.example/superproject-common
:exoscale.project/version-file "VERSION"
:exoscale.project/modules ["." "modules/client" "modules/server"]
:paths ["src" "resources"]
:deps {org.clojure/clojure {:mvn/version "1.11.1"}}}tools.project supports seamless transitions from standalone projects
to multi module ones. See add-module for
help on how to add a first module.
The easiest way is to pass JAVA_OPTS env variable to the clj invocation and then connect a remote debugger (via eg: IntelliJ):
JAVA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005" clj -T:project checkAlternatively, it's possible to call the task directly from your clojure REPl, provided you supply the project alias.
Then, you can use your emacs/vim/IDE to debug possible issues.
$ clj -A:project
Clojure 1.12.2
user=> (require 'exoscale.tools.project)
nil
user=> (exoscale.tools.project/check nil)
running prep task for dependencies in: exoscale/partner-api
storing git sha in resources/git-version
Downloading: org/spootnik/deps-check/0.5.2/deps-check-0.5.2.pom from clojars
Downloading: org/spootnik/deps-check/0.5.2/deps-check-0.5.2.jar from clojars
compiling namespace partner-api.basic-handlers
...When developing against tools.project, due to the presence of a
project.clj namespace in the repository, if you use cider, you'll
have to jack in from the top level directory, otherwise cider gets
confused and tries to treat the repository as a leiningen one.