From 41d9b6eb914e85ec821fd92a20726797f05992b4 Mon Sep 17 00:00:00 2001 From: John Practicalli <250870+practicalli-john@users.noreply.github.com> Date: Thu, 19 Oct 2023 20:51:40 +0100 Subject: [PATCH] project: tools.build updated approach and configuration --- CHANGELOG.md | 1 + .../projects/package/tools-build.md | 216 ++++++++++++++---- 2 files changed, 173 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3210da890..51369abc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/docs/clojure-cli/projects/package/tools-build.md b/docs/clojure-cli/projects/package/tools-build.md index ba537f71c..55dae912f 100644 --- a/docs/clojure-cli/projects/package/tools-build.md +++ b/docs/clojure-cli/projects/package/tools-build.md @@ -1,4 +1,4 @@ -# 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. @@ -6,13 +6,11 @@ The following files are created in each project that uses tools.build: -* `build.clj` contains a namespace with tasks -* `:project/build` alias containing tools.build library and sets the default namespace - -`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 +- `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 @@ -21,24 +19,34 @@ 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 @@ -46,46 +54,166 @@ 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 +### Project configuration - If arguments are not given on the command line, a `nil` value is passed to the called function +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. + + ```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 + ;; --------------------------------------------------------- + ``` - `_` name convention is used when a function definition does not make use of the argument that is passed +### Clean Task -!!! EXAMPLE "tools.build tasks configuration" +??? 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 @@ -136,7 +264,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,