DWN -- A Clojure launcher via Nix(OS)
Installation
Nix
For now, you need the Nix package manager installed. This is most easily done by
curl https://nixos.org/nix/install | sh
Installing from checkout
There is rudimentary command line tooling, in the form of a dwn
command. You can build it with:
nix-build shell.nix -A dwnTool
Install it to your user profile with:
nix-env -i ./result
Now, the dwn
command should be in your $PATH
.
Usage
You need a project.nix
file. Most easily, this can be written by delegating to a Leiningen project:
{ fromLein }:
fromLein ./project.clj {
devMode = false;
closureRepo = ./project.repo.edn;
}
You can try the following commands with the example/leiningen
project.
With the project.nix
file in place, you need to generate a
repository file for the project. That file holds all the sha1
s for
you dependency artifacts, similar to a php-composer
lockfile. This
command generates the repo file in project.repo.edn
, which is meant
to be checked in:
dwn gen-repo ./project.nix
After having generated the repo file, you can build the project:
dwn build ./project.nix
This generates ./result
with a classpath for your project, along
with shell launchers for your main namespaces.
It is idiomatic, to run your project like this:
$(dwn build ./project.nix --no-out-link)/bin/main
That command will rebuild your project before running it, if changed.
Advanced usage
For lack of a leiningen descriptor, or if you need to do something
that's not supported by the leiningen descriptor reader, you can
override any option to dwn's native project descriptor. See
src/nix/lib/make-project.nix
. E.g. to use custom repositories:
{ fromLein, defaultMavenRepos }:
fromLein ./project.clj {
devMode = false;
closureRepo = ./project.repo.edn;
mavenRepos = defaultMavenRepos ++ [ https://maven.repository.redhat.com/ga/ ];
}
Dev Notes
The entry path is shell.nix -> default.nix -> packages.nix
There is some interesting bootstrapping going on between
deps.aether/default.nix
and deps.expander/default.nix
, but
project.nix
is already a fully formed project descriptor for the
webnf.dwn
runtime library.
Philosophy
Why?
Nix is a lazy, dynamically typed functional language, that is designed to produce immutable filesets via build recipes. It is also a package manager for software on Linux, OSX, Windows and Hurd. It lets you use all of that software to complete your build recipes and it has awesome ways for distributing the result of your own build recipes.
Clojure, on the other hand is a strict, dynamically typed functional language, that is designed to utilize immutability in application-level code. This means, that by using Nix, we can build a rock solid foundation to run clojure on, including options for spinning it up in the cloud, in containers or vms, via NixOS.
Clojure goes onto Nix, like jam onto bread. Or, as Alex Miller put it at EuroClojure '17: "They are cut from the same cloth".
Jam and bread do call for butter, though, i.e. tooling to bring out the flavor.
How?
Like Nix(OS), DWN isn't peanut butter. It isn't very opinionated. Instead, it's just plain butter, that underscores the the flavors, already there.
What?
DWN is tooling to:
- generate a project.repo.edn file with checksums of maven artifacts,
that can be committed to SCM
- this contains the whole graph of muliple version per coordinate, discovered by the dependency crawler in deps.aether
- use a custom, most-recent wins strategy, to always select newer
versions from repo.edn, in order to build a classpath
- in addition to most-recent-wins, this retains a partial ordering on the classpath, where a referrer would usually be able to override its dependents' resource paths (except when they are on the wrong side of a dependency cycle)
- generate runners for your clojure code
- shell launchers
- systemd .service files (to be exposed via
dwn
) - edn descriptors, that can be started in webnf.dwn container within
an existing java process (to be exposed via
dwn
)
- compile namespaces to jvm byte code, before building the classpath
- switch between dev mode, where generated artifacts would point into a working direcory vs. {dev false}, where everything is content-hashed into /nix/store.
Could?
- DWN could be folded into a bin/dwn script + a .local/share/dwn state directory The script could mimic a more traditional dependency+build+distribution - tool, by tying together the existing functionality and thus be more readily accessible to UNIX users, while still providing the benefit of stable builds and a vast "standard library" for clojure.java.shell