{ lib, stdenv, callPackage, clojure, jre, writeText, writeShellScript, toEDN }: { src, name, group, version, clj-deps, src-paths, ... }: with lib; let classpath = clj-deps.makeClasspaths { }; deps-jars = splitString ":" classpath; full-name = "${name}-${version}-standalone"; manifest = writeText "MANIFEST.MF" '' Manifest-Version: 1.0 ''; extract-jar = jar: '' echo jar -xf ${jar} jar -xf ${jar} ''; clj-compile = classpath: ns: '' echo java -cp .:${classpath} clojure.main -e "(compile ${ns})" java -cp .:${classpath} clojure.main -e "(compile ${ns})" ''; matches-ext = ext: filename: (builtins.match ".+[.]${ext}$" filename) != null; strip-ext = ext: filename: builtins.head (builtins.match "(.+)[.]${ext}$" filename); concatMapAttrs = f: attrs: concatLists (mapAttrsToList f attrs); find-files = pred: path: let find-files-impl = base: concatMapAttrs (handle-file base) (builtins.readDir base); handle-file = base: name: type: if (type == "directory") then find-files-impl "${base}/${name}" else (if (pred name) then [ "${base}/${name}" ] else [ ]); in find-files-impl path; file-to-namespace = base: filename: let swap-chars = replaceStrings [ "_" "/" ] [ "-" "." ]; strip-clj = strip-ext "clj"; strip-base = replaceStrings [ "${base}/" ] [ "" ]; ns = swap-chars (strip-base (strip-clj (toString filename))); in "'${ns}"; target-namespaces = concatMap (subdir: let dir = src + "/${subdir}"; in map (file-to-namespace dir) (find-files (matches-ext "clj") dir)) src-paths; copy-source-path = target: subdir: "cp -R ${src}/${subdir}/* ${target}"; build-script = let join-lines = concatStringsSep "\n"; srcs = concatStringsSep ":" (map (path: "./${path}") src-paths); in writeShellScript "create-${full-name}-uberjar.sh" '' HOME=./home mkdir $HOME mkdir classes mkdir ./deps cd ./deps ${join-lines (map extract-jar deps-jars)} cd .. ${join-lines (map (clj-compile "${classpath}:${srcs}:./deps") target-namespaces)} mkdir target cp -R classes/* target/ ${join-lines (map (copy-source-path "./target/") src-paths)} cp -R deps/* target/ cp ./deps.edn ./target/deps.edn cd target jar cmf ${manifest} ../out.jar -C . ./* ''; pthru = o: builtins.trace o o; in stdenv.mkDerivation { name = "${full-name}.jar"; src = src; nativeBuildInputs = [ jre ]; buildInputs = map (x: x.paths) clj-deps.packages; buildPhase = "${build-script}"; installPhase = '' mv out.jar $out ''; }