---
name: "dh-clojure-lein"
section: "7"
platform: "linux"
package: "dh-clojure"
version: "0.2.0"
release: "Debian 13 (Trixie)"
platforms: ["linux"]
url: "https://new.carta.tech/dh-clojure-lein"
---

# dh-clojure-lein(7)

Debhelper support for Leiningen projects

## NAME

dh-clojure-lein - Debhelper support for Leiningen projects

## DESCRIPTION

Support for Leiningen projects consists of a Debhelper build system, available via the **dh** **--buildsystem** argument, and support for automatic and customizable adjustments to projects.

Currently under development, and should not be considered stable until (at least) the dh-clojure major version is no longer 0 and this notice changes.

## USAGE

### Buildsystem

The build system is designed to facilitate packaging Leiningen-based Clojure projects for Debian, and can be activated by passing the **--buildsystem=leiningen** option to **dh**:

```
 %:
    dh $@ --buildsystem=leiningen
```

It takes action during these debhelper stages:

- **configure**

  Sets up a debian/dh-clojure/tmp/maven-repo symlink pointing to /usr/share/maven-repo for use by lein as a :local-repo.

- **build**

  Creates a debian/dh-clojure/tmp/pom.xml for use in the debian/PACKAGENAME.poms file (which it also creates), and it creates an unversioned symlink in target/ for the jar.

- **install**

  Calls helpers from the **maven-repo-helper** package to install the built jars into /usr/share/java and poms and jar symlinks in /usr/share/maven-repo and generate the ${maven:Depends} substitution variable.

- **test**

  Runs `"lein test"`.

- **clean**

  Runs `"lein clean"` and cleans up after the previous steps.

### Project Adjustment (middleware)

The Leiningen *project.clj* will be automatically adjusted by the buildsystem (see above).  By default, it will set all of the dependency versions in the project to "debian", excepting `"org.clojure/clojure"`, which will be set to "1.x".

The project adjustments may be customized by code in an optional *debian/dh-clojure-lein.clj* file.  That file may define an `"dh-clj-adjust-project"` function which will be invoked like this:

```
  (dh-clj-adjust-project get-project when ...)
```

The first argument is a function that returns the Leiningen project map.  The second argument indicates the current point in the project build sequence.  At the moment it will be `":before-plugins"` or `":after-middleware"`, but to allow for future changes, unexpected values should be ignored, as should additional arguments. `"dh-clj-adjust-project"` must return the `"(get-project)"` map after any adjusments.  See EXAMPLES below.

An `":after-middleware"` call can assume that the project map has been adjusted by a preceding `":before-plugins"` call, and a call for a given keyword may be made more than once, so any actions must be repeatable.

When making dependency adjustments, any changes to `":plugins"` should be done during `":before-plugins"` invocations, and other dependency changes should normally be made during `":after-middleware"` invocations.

Note that all definition names starting with `"dh-clj"` are reserved by dh-clojure-lein.

In the project map passed to `"dh-clj-adjust-project"` the values of the dependency-related entries `":dependencies"`, `":managed-dependencies"`, and `":plugins"` are not dependency vectors (as in *project.clj*), but are in leiningen's dependency \*map\* format, which is more suitable for manipulation.  For example

```
  [[org.clojure/clojure "42.x"]]
```

is represented as

```
  {{:group-id "org.clojure", :artifact-id "clojure"}
   {:artifact-id "clojure", :group-id "org.clojure", :version "42.x"}}
```

Though in most cases, this won't be important because the following client functions (defined in `"debian.dh-clojure-lein.client"`) handle the common project manipulations (see the EXAMPLES section below). Note that only the public functions in `"client"` are part of the stable API.  Other functions in dh-clojure-lein should not be invoked via `"dh-clojure-lein.clj"`.

- (add-dep DEP-MAP DEP-SPEC)

  Adds the dependency specified by DEP-SPEC (the dependency must not be present in the original project).

- (del-dep DEP-MAP DEP-KEY)

  Removes the dependency specified by DEP-KEY (the dependency must be present in the original project).

- (set-dep DEP-MAP DEP-KEY FIELD VALUE)

  Sets the specified FIELD (`":version"` or `":exclusions"`) of the dependency specified by DEP-VEC to the given value (the dependency must be present in the original project).  Setting `":exclusions"` to `"nil"` will remove all exclusions from the dependency.

- (get-dep DEP-MAP DEP-SPEC \[default\])

  Behaves exactly like `"clojure.core/get"`, returning the `"{:group-id` `...}"` map in DEP-MAP, if any.

A *DEP-KEY* is the subset of a lein project dependency vector that uniquely identifies a dependency, either a symbol like `"org.clojure/tools.cli"` or a a lein project dependency vector starting with that symbol, optionally followed by a `":classifier"`, and/or `":extension"`, for example `"[org.clojure/tools.cli :classifier` `"test"]"`.

A *DEP-SPEC*s is a lein project dependency vector with the exception that it may omit the version, for example `"[org.clojure/tools.cli` `"1.x"]"` or `"[org.clojure/tools.cli :classifier "test"]"`.

Note that unless otherwise specified, the default value for all dependencies will be set to either `"debian"`, or for `"org.clojure/clojure"`, to "1.x".

Some adjustments should only apply when specific profiles are active, for example, removing a dependency in a test profile.  The active profile(s) can be investigated via

- (active-profiles PROJECT)

  Returns a sequence of the active profiles like `"(:base :system :user` `:provided :dev)"`.  So to check whether the `":test"` profile is active: `"(some #{:test} (active-profiles PROJECT))"`.

Emacs clojure-mode and paredit (via elpa-clojure-mode and elpa-paredit in Debian) can be quite helpful if you're editing a lot of these files.  They provide automatic indentation, highlighting, structural editing, etc.

## EXAMPLES

### Project adjustments

See the Clojure API \<https://clojure.github.io/clojure/clojure.core-api.html#clojure.core\> for documentation of specific calls like `"assoc"`, `"update"`, and `"->"`.

Remove a plugin:

```
 (require '[debian.dh-clojure-lein.client :as deb])
 (defn dh-clj-adjust-project [project when & _]
   (if-not (= when :before-plugins)
     (project)
     (update :plugins deb/del-dep 'lein-pprint)))
```

Adjust dependency:

```
 (require '[debian.dh-clojure-lein.client :as deb])
 (defn dh-clj-adjust-project [project when & _]
   (if (= when :after-middleware)
     (update (project) :dependencies deb/set-dep 'y :version "5.x"))
     (project))
```

Adjust more dependencies:

```
 (require '[debian.dh-clojure-lein.client :as deb])
 (defn adjust-deps [deps]
   (-> deps
       (deb/add-dep '[w "1.x"])
       (deb/add-dep 'org.clojure/core.match)
       (deb/del-dep 'murphy)
       (deb/set-dep 'y :version "5.x")
       (deb/set-dep 'y :exclusions nil) ;; delete exclusions
       (deb/set-dep '[x/y :classifier "test"] :version "5.x")))
 (defn dh-clj-adjust-project [project when & _]
   (if (= when :after-middleware)
     (update (project) :dependencies adjust-deps)
     (project)))
```

Equivalently:

```
 (require '[debian.dh-clojure-lein.client :as deb])
 (defn dh-clj-adjust-project [project when & _]
   (if-not (= when :after-middleware)
     (project)
     (-> (project)
       (assoc :version "11.x")
       (update :dependencies deb/add-dep '[w "1.x"])
       (update :dependencies deb/add-dep 'org.clojure/core.match)
       (update :dependencies deb/del-dep 'murphy)
       (update :dependencies deb/set-dep 'y :version "5.x")
       (update :dependencies deb/set-dep '[x/y :classifier "test"] :version "5.x"))))
```

Make profile-specific adjustments:

```
 (require '[debian.dh-clojure-lein.client :as deb])
 (defn adjust-deps [deps proj]
   (let [test? (some #{:test} (deb/active-profiles proj))
         dev? (some #{:dev} (deb/active-profiles proj))]
     (cond-> deps
       true (deb/add-dep '[w "1.x"])
       dev? (deb/add-dep 'a/b)
       test? (deb/del-dep 'murphy)
       true (deb/set-dep 'x :version "5.x")
       true (deb/set-dep '[x/y :classifier "test"] :version "5.x"))))
 (defn dh-clj-adjust-project [project when & _]
   (let [proj (project)]
     (if (= when :after-middleware)
       (update proj :dependencies adjust-deps proj)
       proj)))
```

Equivalently:

```
 (require '[debian.dh-clojure-lein.client
            :refer [active-profiles add-dep set-dep]])
 (defn fix-shared [deps]
   (-> %
       (add-dep '[w "1.x"])
       (set-dep 'x :version "5.x")
       (set-dep '[x/y :classifier "test"] :version "5.x")))
 (defn adjust-deps [deps proj]
   (let [test? (some #{:test} (active-profiles proj))
         dev? (some #{:dev} (active-profiles proj)])
     (cond
       test? (-> deps fix-shared (add-dep 'a/b))
       dev? (-> deps fix-shared (del-dep 'murphy))
       :else (fix-shared deps))))
 (defn dh-clj-adjust-project [project when & _]
   (let [proj (project)]
     (if (= when :after-middleware)
       (update proj :dependencies adjust-deps proj)
       proj)))
```

Remove a dependency that might not exist:

```
  (cond-> deps
    ...
    (deb/get-dep deps 'x/y) (deb/del-dep 'x/y)
    ...)
```

For debugging, you can use Clojure's existing print statements, for example:

```
  (prn :active (active-profiles))
```

And for more readable output that can be inserted directly into the threading forms (e.g. `"->"` and `"-><gt"`\>), you can do something like this:

```
  (require 'clojure.pprint)
  (defn spy> [x tag]
    (binding [*out* *err*] (clojure.pprint/pprint [tag x]))
    x)
  (defn spy>> [tag x]
    (binding [*out* *err*] (clojure.pprint/pprint [tag x]))
    x)
 ...
 (defn fix-shared [deps]
   (-> %
       (add-dep '[w "1.x"])
       (spy> :after-w)
       (set-dep 'x :version "5.x")
       (spy> :after-version)
       (set-dep '[x/y :classifier "test"] :version "5.x")))
```

## ENVIRONMENT

- **DEB\_DH\_CLJ\_INSTALL\_TEST\_JAR**

  If the project is built to generate a "test" jar artifact, setting this environment variable to `"true"` will instruct dh-clojure to include it in the package

- **DEB\_DH\_CLJ\_LEIN\_CREATE\_MAVEN\_REPO** (internal)

  During testing this is set in the environment, and when set, causes the buildsystem to use the value as the command to create the `"debian/dh-clojure/tmp/maven-repo"`.  This is used to provide a writable `"maven-repo"` instead of the normal symlink to `"/usr/share/..."`.

- **DEB\_DH\_CLJ\_LEIN\_BUILD** (internal)

  During the build, this is set to `"true"` in `"lein"`'s environment, and when that's the case and dh-clojure is installed, Debian's `"lein"` will invoke `"debian.dh-clojure-lein/adjust-project"` at various points during the build to allow the calls to `"dh-clj-adjust-project"` described above.

  Since Debian might not package some of the plugins, or might package versions that differ from those specified in *project.clj* adjustments must be made before Leiningen attempts to find them.  That means that they cannot be handled by a dh-clojure-lein middleware (e.g. a plugin).

- **LEIN\_HOME** (internal)

  `"LEIN_HOME"` is set to `"$(pwd)/debian/dh-clojure/tmp/lein-home"` in the environment during the build.

- **LEIN\_OFFLINE** (internal)

  During the build, `"LEIN_OFFLINE"` is set to `"true"` in the environment to ensure that `"lein"` doesn't attempt to retrieve any dependencies from the network

## FILES

*debian/dh-clojure-lein.clj*

## SEE ALSO

[**dh-clojure**(7)](/dh-clojure/7.md), [**dh**(1)](/dh/1.md), [**lein**(1)](/lein/1.md), and \<https://clojure.github.io/clojure/clojure.core-api.html\>
