Welcome! Please see the About page for a little more info on how this works.

+2 votes
in tools.build by
edited by

I'm creating an uberjar with

build=> (b/uber {:class-dir class-dir
                 :uber-file "uberjar.jar"
                 :basis     basis})

This throws an error

build=> (b/uber {:class-dir class-dir
                 :uber-file "uberjar.jar"
                 :basis     basis})
Execution error (FileNotFoundException) at java.io.FileOutputStream/open0 (FileOutputStream.java:-2).
/var/folders/_h/3fpgc8pj4fb2_w3mfqfl59fr0000gn/T/uber8421760143696109740/license/LICENSE (Not a directory)
build=> *e
#error {
 :cause "/var/folders/_h/3fpgc8pj4fb2_w3mfqfl59fr0000gn/T/uber8421760143696109740/license/LICENSE (Not a directory)"
 [{:type java.io.FileNotFoundException
   :message "/var/folders/_h/3fpgc8pj4fb2_w3mfqfl59fr0000gn/T/uber8421760143696109740/license/LICENSE (Not a directory)"
   :at [java.io.FileOutputStream open0 "FileOutputStream.java" -2]}]
 [[java.io.FileOutputStream open0 "FileOutputStream.java" -2]
  [java.io.FileOutputStream open "FileOutputStream.java" 298]
  [java.io.FileOutputStream <init> "FileOutputStream.java" 237]
  [java.io.FileOutputStream <init> "FileOutputStream.java" 187]
  [clojure.tools.build.tasks.uber$explode invokeStatic "uber.clj" 66]
  [clojure.tools.build.tasks.uber$explode invoke "uber.clj" 53]
  [clojure.tools.build.tasks.uber$uber$fn__16290 invoke "uber.clj" 114]
  [clojure.core$run_BANG_$fn__8813 invoke "core.clj" 7717]
  [clojure.core.protocols$naive_seq_reduce invokeStatic "protocols.clj" 62]
  [clojure.core.protocols$interface_or_naive_reduce invokeStatic "protocols.clj" 72]
  [clojure.core.protocols$fn__8181 invokeStatic "protocols.clj" 169]
  [clojure.core.protocols$fn__8181 invoke "protocols.clj" 124]
  [clojure.core.protocols$fn__8136$G__8131__8145 invoke "protocols.clj" 19]
  [clojure.core.protocols$seq_reduce invokeStatic "protocols.clj" 31]
  [clojure.core.protocols$fn__8166 invokeStatic "protocols.clj" 75]
  [clojure.core.protocols$fn__8166 invoke "protocols.clj" 75]
  [clojure.core.protocols$fn__8110$G__8105__8123 invoke "protocols.clj" 13]
  [clojure.core$reduce invokeStatic "core.clj" 6830]
  [clojure.core$run_BANG_ invokeStatic "core.clj" 7712]
  [clojure.core$run_BANG_ invoke "core.clj" 7712]
  [clojure.tools.build.tasks.uber$uber invokeStatic "uber.clj" 114]
  [clojure.tools.build.tasks.uber$uber invoke "uber.clj" 104]
  [clojure.lang.Var invoke "Var.java" 384]
  [clojure.tools.build.api$uber invokeStatic "api.clj" 277]
  [clojure.tools.build.api$uber invoke "api.clj" 266]
  [build$eval16234 invokeStatic "NO_SOURCE_FILE" 11]
  [build$eval16234 invoke "NO_SOURCE_FILE" 11]
  [clojure.lang.Compiler eval "Compiler.java" 7181]
  [clojure.lang.Compiler eval "Compiler.java" 7136]
  [clojure.core$eval invokeStatic "core.clj" 3202]
  [clojure.core$eval invoke "core.clj" 3198]
  [clojure.main$repl$read_eval_print__9110$fn__9113 invoke "main.clj" 437]
  [clojure.main$repl$read_eval_print__9110 invoke "main.clj" 437]
  [clojure.main$repl$fn__9119 invoke "main.clj" 458]
  [clojure.main$repl invokeStatic "main.clj" 458]
  [clojure.core.server$repl invokeStatic "server.clj" 180]
  [clojure.core.server$repl invoke "server.clj" 180]
  [clojure.lang.AFn applyToHelper "AFn.java" 152]
  [clojure.lang.AFn applyTo "AFn.java" 144]
  [clojure.lang.Var applyTo "Var.java" 705]
  [clojure.core$apply invokeStatic "core.clj" 667]
  [clojure.core.server$accept_connection invokeStatic "server.clj" 73]
  [clojure.core.server$start_server$fn__8902$fn__8903$fn__8905 invoke "server.clj" 117]
  [clojure.lang.AFn run "AFn.java" 22]
  [java.lang.Thread run "Thread.java" 829]]}

This error is actually thrown from two libs on our classpath:
- .m2/repository/xml-apis/xml-apis/1.4.01/xml-apis-1.4.01.jar
- .m2/repository/xml-apis/xml-apis-ext/1.3.04/xml-apis-ext-1.3.04.jar

Each of these has an entry license/LICENSE. The problem seems to arise that I am on osx which uses a case insensitive but case-preserving filesystem and there is already a top-level LICENSE file from another jar. So it cannot create a license/LICENSE entry in addition to a LICENSE file that already exists.

I repod this with the following code that creates a few jars:

(ns build
  (:require [clojure.tools.build.api :as b]))

;; create a jar with just a single namespace and a license/LICENSE file
(b/write-file {:path "target/liba/a.clj"
               :content (symbol "(ns a)")})
(b/write-file {:path "target/liba/license/LICENSE"
               :content (symbol "this is the license from a")})
(b/write-file {:path "target/liba/deps.edn"
               :content '{:paths ["."]}})
(b/write-pom {:basis (b/create-basis {:project "target/liba/deps.edn"})
              :class-dir "target/liba"
              :lib 'liba/liba
              :version "1.0.0"
              :src-dirs ["target/liba"]})
(b/jar {:class-dir "target/liba"
        :jar-file "target/jars/liba.jar"})

;; create another jar libb with just a single ns and a license file
(b/write-file {:path "target/libb/b.clj"
               :content (symbol "(ns b)")})
(b/write-file {:path "target/libb/license"
               :content (symbol "this is the license from b")})
(b/write-file {:path "target/libb/deps.edn"
               :content '{:paths ["."]}})
(b/write-pom {:basis (b/create-basis {:project "target/libb/deps.edn"})
              :class-dir "target/libb"
              :lib 'libb/libb
              :version "1.0.0"
              :src-dirs ["target/libb"]})
(b/jar {:class-dir "target/libb"
        :jar-file "target/jars/libb.jar"})

;; create a consumer of these
(b/write-file {:path "target/libc/license"
               :content (symbol "this is the license from c")})
(b/write-file {:path "target/libc/deps.edn"
               :content '{:deps {liba/liba {:local/root "../jars/liba.jar"}
                                 libb/libb {:local/root "../jars/libb.jar"}}}})

(def old-project-root b/*project-root*)
(b/set-project-root! "target/libc")
#_(b/set-project-root! old-project-root)

(b/uber {:class-dir "."
         :uber-file "uberjar.jar"
         :basis (b/create-basis {:project "deps.edn"})
         :main 'clojure.main})

But the basic error happens when trying to explode the jars and creating a folder license when a file LICENSE already exists.

Sean mentioned that depstar has an api-compatible uber function and that has worked for me. Since the contents of the jars never hit the filesystem this constraint is avoided.

1 Answer

+2 votes