Skip to content

Commit

Permalink
project: tools.build updated approach and configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
practicalli-johnny committed Oct 19, 2023
1 parent 71e1b43 commit a390fa2
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 46 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

## Changed
- mkdocs: emoji extension name update for Material 9.4
- project: update built.tools approach and configuration examples

# 2023-08-14

Expand Down
222 changes: 176 additions & 46 deletions docs/clojure-cli/projects/package/tools-build.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
# Clojure tools.build
# Package projects with tools.build

[:globe_with_meridians: Clojure.org tools.build](https://clojure.org/guides/tools_build) is a library to define build related tasks using Clojure code.
!!! WARNING "Page being updated with enhanced examples"

[:globe_with_meridians: tools.build API](https://clojure.github.io/tools.build/) provides a consistent interface to access the project configuration (project basis) and common tasks that facilitate building and packaging projects.
[:globe_with_meridians: Clojure.org tools.build](https://clojure.org/guides/tools_build) is a library to define build related tasks using Clojure code.

The following files are created in each project that uses tools.build:
The [:globe_with_meridians: tools.build API](https://clojure.github.io/tools.build/) provides a consistent interface to access the project configuration (project basis) and common tasks that facilitate building and packaging projects.

* `build.clj` contains a namespace with tasks
* `:project/build` alias containing tools.build library and sets the default namespace
Include a build alias and build script in each project that should use tools.build:

`clojure -T:build task-name` to run any of the tasks defined in the default `build` namespaces.
- `:build/task` alias adding tools.build library to the class path in the project `deps.edn` file
- `build.clj` defines a namespace requiring tools.build, a project configuration and functions as build tasks

??? HINT "Practicalli Project Templates include tools.build tasks"
[:fontawesome-solid-book-open: Practicalli Project templates](/clojure/clojure-cli/projects/templates/) include a `build.clj` configuration with `jar` and `uberjar` tasks.
[:fontawesome-solid-book-open: Practicalli Project templates](/clojure/clojure-cli/projects/templates/) include a `build.clj` tasks to generate a library `jar` or a service `uberjar`.


## Define a build alias
Expand All @@ -21,71 +21,201 @@ Add an alias to the project `deps.edn` file which includes the `org.clojure/tool

!!! EXAMPLE "Alias to include tools.build library"
```clojure title="Project deps.edn"
:project/build

;; tools.build `build.clj` built script
:build/task
{:replace-paths ["."]
:replace-deps {io.github.clojure/tools.build
{:git/tag "v0.9.4" :git/sha "76b78fe"}}
{:git/tag "v0.9.6" :git/sha "8e78bcc"}}
:ns-default build}
```

Use Clojure CLI to run any of the tasks defined in the `build` namespaces.

```shell
clojure -T:build/task task-name
```


??? INFO "tools.build release information"
[Clojure.org tools.build release information](:fontawesome-brands-github: https://github.com/clojure/tools.build#release-information) shows the current values for `git/tag` and `:git/sha`


??? INFO "Developing code in the build script"
`:replace-paths ["."]` includes the `build.clj` file on the class path to allow for REPL development of the build tasks

Include `:build` alias in the Clojure command when starting the REPL.
```shell
clojure -M:project/build:repl/rebel
clojure -M:build/task:repl/rebel
```

??? INFO "tools.build release information"
[Clojure.org tools.build release information](:fontawesome-brands-github: https://github.com/clojure/tools.build#release-information) shows the current values for `git/tag` and `:git/sha`


## Build Script

Create a `build.clj` file to contain the build configuration and tasks.

Define the namespace and require the clojure.tools.build.api library

```clojure title="build.clj"
(ns build
(:require [clojure.tools.build.api :as build-api]))
```

Define a configuration for the build with values used in the build tasks.

```clojure title="build.clj"
;; ---------------------------------------------------------
;; Build configuration

(def project-config
"Project configuration to support all tasks"
(let [library-name 'practicalli/clojure-app-template
version (format "1.0.%s" (build-api/git-count-revs nil))]
{:library-name library-name
:main-namespace library-name
:project-version version
:class-directory "target/classes"
:project-basis (build-api/create-basis)
:jar-file (format "target/%s-%s.jar" (name library-name) version)
:uberjar-file (format "target/%s-%s-standalone.jar" (name library-name) version)}))

;; End of Build configuration
;; ---------------------------------------------------------
```
=== "Service Uberjar"

!!! EXAMPLE "Namespace definition with tools.build.api and Pretty Print"
```clojure title="build.clj"
(ns build
(:require
[clojure.tools.build.api :as build-api]
[clojure.pprint :as pprint]))
```

=== "Service Uberjar"

Define functions to support common tasks `clean`, `jar`, `uberjar`

!!! INFO "Functions are passed command line arguments"
Function definitions should accept an argument as they are sent command line options when called via the `clojure -T:build` command

If arguments are not given on the command line, a `nil` value is passed to the called function
### Project configuration

`_` name convention is used when a function definition does not make use of the argument that is passed
Define a hash-map containing keys and values required to build the project.

=== "Service Uberjar"
Define a project configuration for building an Uberjar file to run a service using the `java -jar` command.

The Uberjar can be deployed to run the service in test, staging and production environments.

!!! EXAMPLE "tools.build tasks configuration"
```clojure title="build.clj"
;; ---------------------------------------------------------
;; Project configuration

(def project-config
"Project configuration to support build tasks"
{:class-directory "target/classes"
:main-namespace 'practicalli/project-name/service
:project-basis (build-api/create-basis)
:uberjar-file "target/practicalli-servicename-standalone.jar"})

(defn config
"Display build configuration"
[config]
(pprint/pprint (or config project-config)))

;; End of Build configuration
;; ---------------------------------------------------------
```


=== "Library Jar"
Define a project configuration for building a jar file for deployment on Clojars and Maven Central, or a private repository.

```clojure title="build.clj"
;; ---------------------------------------------------------
;; Build configuration

(def project-config
"Project configuration to support build tasks"
(let [library-name 'practicalli/library-name
version (format "1.0.%s" (build-api/git-count-revs nil))]
{:library-name library-name
:main-namespace library-name
:project-version version
:class-directory "target/classes"
:project-basis (build-api/create-basis)
:jar-file (format "target/%s-%s.jar" (name library-name) version)}))

(defn config
"Display build configuration"
[config]
(pprint/pprint (or config project-config)))
;; End of Build configuration
;; ---------------------------------------------------------
```

### Clean Task


??? EXAMPLE "tools.build uberjar task configuration"
```clojure title="build.clj"
;; ---------------------------------------------------------
;; Build Script
;;
;; Build project and package for deployment
;; - `uberjar` - packaged application for deployment
;; - `clean` remove all build assets and jar files
;;
;; All functions are passed command line arguments
;; - `nil` is passed if there are no arguments
;;
;;
;; tools.build API commands
;; - `create-basis` create a project basis
;; - `copy-dir` copy Clojure source and resources into a working dir
;; - `compile-clj` compile Clojure source code to classes
;; - `delete` - remove path from file space
;; - `write-pom` - write pom.xml and pom.properties files
;; - `jar` - to jar up the working dir into a jar file
;;
;; ---------------------------------------------------------

(ns build
(:require
[clojure.tools.build.api :as build-api]
[clojure.pprint :as pprint]))

;; ---------------------------------------------------------
;; Project configuration

(def project-config
"Project configuration to support all tasks"
{:class-directory "target/classes"
:main-namespace 'practicalli/bob-the-builder
:project-basis (build-api/create-basis)
:uberjar-file "target/practicalli-service-name-standalone.jar"})

(defn config
"Display build configuration"
[config]
(pprint/pprint (or config project-config)))

;; End of Build configuration
;; ---------------------------------------------------------

;; ---------------------------------------------------------
;; Build tasks

(defn clean
"Remove a directory
- `:path '\"directory-name\"'` for a specific directory
- `nil` (or no command line arguments) to delete `target` directory
`target` is the default directory for build artefacts
Checks that `.` and `/` directories are not deleted"
[directory]
(when
(not (contains? #{"." "/"} directory))
(build-api/delete {:path (or (:path directory) "target")})))


(defn uberjar
"Create an archive containing Clojure and the build of the project
Merge command line configuration to the default project config"
[options]
(let [config (merge project-config options)
{:keys [class-directory main-namespace project-basis uberjar-file]} config]
(clean "target")
(build-api/copy-dir {:src-dirs ["src" "resources"]
:target-dir class-directory})

(build-api/compile-clj {:basis project-basis
:class-dir class-directory
:src-dirs ["src"]})

(build-api/uber {:basis project-basis
:class-dir class-directory
:main main-namespace
:uber-file uberjar-file})))

;; End of Build tasks
;; ---------------------------------------------------------



??? EXAMPLE "tools.build jar task configuration"
;; ---------------------------------------------------------
;; Build tasks

Expand Down Expand Up @@ -136,7 +266,7 @@ Define functions to support common tasks `clean`, `jar`, `uberjar`
;; ---------------------------------------------------------
```

!!! EXAMPLE "Project configuration"
??? EXAMPLE "Project configuration"
Pretty printed Example of a project configuration
```clojure
{:library-name practicalli/clojure-app-template,
Expand Down

0 comments on commit a390fa2

Please sign in to comment.