jlesquembre / clj-nix

Nix helpers for Clojure projects
https://jlesquembre.github.io/clj-nix/
Eclipse Public License 2.0
146 stars 22 forks source link

Support Babashka #37

Closed jlesquembre closed 1 year ago

jlesquembre commented 1 year ago

See https://github.com/clojure-lsp/clojure-lsp/issues/1373

ikappaki commented 1 year ago

Hi,

I was about to open an issue for the same with a reproducible example using clj-nix demo project, when I noticed this, so here are my findings in the hope it will give a boost to support babashka in clj-nix.

(cc'ing @borkdude for awareness)

Basically, I can see two issues as it currently stands

  1. The babashka package does not come bundled with the clojure-tools dependencies.
  2. clj-nix does not look into bb.edn's dependencies.

I suppose a solution could be to bundle the clojure-tools (as required by deps.clj) with the babashka nix pkg as well as have clj-nix's deps-lock look into bb.edn when bababshka is used as a build tool.

Below, I firstly provide a reproduction of the issue using the clj-nix demo project building the clj-tuto pkg, and then I walk through a hack to make the build work with babashka, describing the issues along the way.


To reproduce by building an uberjar build command using a build.clj file, so that an uberjar can be build with clojure -T:build uber cmd from babashka.

  1. Checkout clj-nix's clj-demo-project

    $ git clone https://github.com/jlesquembre/clj-demo-project.git issue-cljnix-bb
    $ cd issue-cljnix-bb
    $ git rev-parse HEAD
    # ecc0cbacf79365c22628a3bd8d6ee220c97aed02
  2. update deps

    $ nix run github:jlesquembre/clj-nix#deps-lock
    $ git add deps-lock.json
  3. Add build.clj file to create uber jar, and test that it works

    (ns build
    (:require [clojure.tools.build.api :as b]))
    
    (def lib 'clj-nix/demo)
    (def version (format "1.2.%s" (b/git-count-revs nil)))
    (def class-dir "target/classes")
    (def basis (b/create-basis {:project "deps.edn"}))
    (def uber-file (format "target/%s-%s-standalone.jar" (name lib) version))
    
    (defn clean [_]
    (b/delete {:path "target"}))
    
    (defn uber [_]
    (clean nil)
    (b/copy-dir {:src-dirs ["src" "resources"]
                 :target-dir class-dir})
    (b/compile-clj {:basis basis
                    :src-dirs ["src"]
                    :class-dir class-dir})
    (b/uber {:class-dir class-dir
             :uber-file uber-file
             :basis basis
             :main 'demo.core}))
$ git add build.clj
$ clj -T:build uber
$ java -jar target/demo-1.2.20-standalone.jar 
# Hello from CLOJURE!!!
  1. create bb.edn task to automate bulding and test it to work

    {:deps {io.github.babashka/tools.bbuild {:git/sha "a3c0723b6250756eaeed532ade5d6474df24e80a"}}
    :tasks
    {uberjar (clojure "-T:build uber")}}
    $ git add bb.edn
    $ rm -fr target
    $ bb uberjar
    $ java -jar target/demo-1.2.20-standalone.jar 
    # Hello from CLOJURE!!!
  2. Update buildInputs and buildCommand in flake.nix clj-tuto pkg to use bb to build the package as an uberjar

          clj-tuto = pkgs.mkCljBin {
                      projectSrc = ./.;
                      buildInputs = [pkgs.babashka pkgs.unzip];
                      name = "me.lafuente/clj-tuto";
                      version = "1.0";
                      main-ns = "demo.core";
                      # jdkRunner = pkgs.jdk17_headless;
    
                      buildCommand = "bb uberjar";
    
                      # mkDerivation attributes
                      doCheck = true;
                      checkPhase = "clj -M:test";
                    };
$ nix build .#clj-tuto
  1. It fails to build with a unknown host exception when bb is trying to download the clojure tools
    
    building
    Could not find /build/.deps.clj/1.11.1.1149/ClojureTools/clojure-tools-1.11.1.1149.jar
    Downloading tools jar from https://download.clojure.org/install/clojure-tools-1.11.1.1149.zip to /build/.deps.clj/1.11>
    Exception in thread "main" java.net.UnknownHostException: download.clojure.org
        at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:229)

This is because babashka does not come bundled with the clojure tools dependency.

Hacking around,  so that all extra dependencies (tools deps, git and bb.edn's :deps) are present

1. Declare clojure tools zip file as flake input and `nix build`; it will then complain about bb can't find git, required for installing the bb.edn's tools.build dependency
``` nix
    # in inputs add
 inputs = {
    #...
    cljtools = {type = "file";
                  url = "https://download.clojure.org/install/clojure-tools-1.11.1.1149.zip";
                  flake = false;
                 };
    };
    # in outputs add cljtools in the fn argument
    outputs = { self, nixpkgs, flake-utils, devshell, clj-nix, cljtools }:

    # update clj-tuto, so that clojure tools are unzipped to magic `/build` directory under the subdirectory pattern expected by bb's 'clojure' command
    clj-tuto = pkgs.mkCljBin {
      projectSrc = ./.;
      buildInputs = [pkgs.babashka pkgs.unzip];
      name = "me.lafuente/clj-tuto";
      version = "1.0";
      main-ns = "demo.core";
      # jdkRunner = pkgs.jdk17_headless;

      buildCommand = ''
    mkdir -p /build/.deps.clj/1.11.1.1149
    unzip ${cljtools} -d /build/.deps.clj/1.11.1.1149
    bb uberjar
  '';
$ nix build .#clj-tuto
# Picked up JAVA_TOOL_OPTIONS: -Duser.home=/nix/store/qk7256k9vjq3kgkp2wjipqf8iq617a8c-clj-cache
# Cloning: https://github.com/babashka/tools.bbuild.git
#Error building classpath. Cannot run program "git": error=2, No such file or directory
  1. add pkgs.gitin flake clj-tuto pkg's buildInputs, and rerun, it complains git can't clone the tools.bbuild dep from github
                      buildInputs = [pkgs.babashka pkgs.unzip pkgs.git];     
$ nix build .#clj-tuto
# Picked up JAVA_TOOL_OPTIONS: -Duser.home=/nix/store/qk7256k9vjq3kgkp2wjipqf8iq617a8c-clj-cache
# Cloning: https://github.com/babashka/tools.bbuild.git
# Error building classpath. Unable to clone /nix/store/8vcf3jn72is5i0lmr7gnj8dqi7mn2bly-gitlibs-config-dir/https/github...
  1. Copy pastebb.edn's deps to deps.edn under an unused alias so that the bb deps are picked up by clj-nix deps-lock fn, and then update deps lock file
    ;; in deps.edn :aliases
    {:aliases
    ;; ...
    :nix-flake {:extra-deps {io.github.babashka/tools.bbuild {:git/sha "a3c0723b6250756eaeed532ade5d6474df24e80a"}}}
    }
$ nix run github:jlesquembre/clj-nix#deps-lock
  1. run nix-build and test that the uberjar works
    $ result/bin/clj-tuto 
    # Hello from CLOJURE!!!   

Hope this helps.

Thanks