Leiningen 不会从 uberjar 中排除命名空间

Leiningen wont exclude namespaces from uberjar

我有一个项目,我希望代码的某些部分能够 运行 在本地环境中,而其他部分依赖于仅 运行 在远程环境中的库。例如

src/app/core.clj <- can run anywhere
src/app/sandbox/remote_only.clj <- depnds on libs that only function in remote environ

其中 src/app/core.clj

(ns app.core
  (:gen-class))
(defn -main [] (println "Hello, World!"))

并且src/app/sandbox/remote_only.clj

(ns app.sandbox.remote-only
  (:require
    [uncomplicate.commons.core :refer [with-release]]
    [uncomplicate.neanderthal
     [native :refer [dv dge]]
     [core :refer [mv mv!]]]))

我希望能够 uberjar 和 运行 位于 core.clj 中的代码在我的本地机器上,而不需要拉入 remote_only.clj ,这将导致程序失败本地。根据文档,Leiningen 应该能够使用配置文件和 uberjar 排除项来完成此操作,例如:

(defproject app "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.10.1"]]
  :profiles {:uberjar {:main app.core
                       :init-ns app.core
                       :aot :all}
             :remote {:init-ns app.sandbox.remote_only
                      :dependencies [[uncomplicate/neanderthal "0.43.1"]]}} ; these deps will fail locally
  :uberjar-exclusions [#".*sandbox.*"]
  :repl-options {:init-ns app.core})

在这里编译 uberjar 将导致:

❯ lein uberjar
Compiling app.core
Compiling app.sandbox.remote-only
Syntax error macroexpanding at (remote_only.clj:1:1).
Execution error (FileNotFoundException) at app.sandbox.remote-only/loading (remote_only.clj:1).
Could not locate uncomplicate/commons/core__init.class, uncomplicate/commons/core.clj or uncomplicate/commons/core.cljc on classpath.

因此,它明确地试图编译被明确排除的 class。

我认为可以通过从 :aot 编译中删除 :all 标记来避免此类问题。例如:

(defproject app "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.10.1"]]
  :profiles {:uberjar {:main app.core
                       :init-ns app.core
                       :aot [app.core]}
             :remote {:init-ns app.sandbox.remote_only
                      :dependencies [[uncomplicate/neanderthal "0.43.1"]]}} ; these deps will fail locally
  :uberjar-exclusions [#".*sandbox.*"]
  :repl-options {:init-ns app.core})

这会导致其他问题:

❯ lein uberjar
Compiling app.core
Created /Users/warrenronsiek/Projects/app/target/app-0.1.0-SNAPSHOT.jar
Created /Users/warrenronsiek/Projects/app/target/app-0.1.0-SNAPSHOT-standalone.jar
~/Projects/app                                                                                                                                                                                              5s 15:47:37
❯ java -jar ./target/app-0.1.0-SNAPSHOT.jar 
Exception in thread "main" java.lang.NoClassDefFoundError: clojure/lang/Var

我试过各种 :exclusions:jar-exclusions 和正则表达式。这个问题的变体已被多次询问 (1, 2) 没有任何效果。

如何让 Leiningen 编译 uberjars 并忽略指定的文件?

我还没有尝试过这种带有“排除项”功能的特殊设置。

一种解决方法是为应用程序的“本地”和“远程”部分创建子项目,然后供更高级别的“总”项目使用。

app
  app-local
  app-remote

其中 3 个中的每一个都是一个单独的 Lein 项目。 app-localapp-remote 可以单独开发。然后,顶级 app 项目使用 2 个子项目作为依赖项(因此仅适用于 remote/full 环境)。

Lein 功能 checkouts 允许您同时在所有 3 个存储库中进行开发,这是一个巨大的帮助。它比使用 lein install 的替代方法要快得多,后者速度慢、手动、重复且容易出错。


P.S。您是否尝试过使用 lein jar 而不是 lein uberjar

:aot :all 更改为 :aot [app.core] 是正确的,但是当您尝试 运行 JAR 时,您 运行 正在 library 版本而不是整个应用程序版本:

java -jar ./target/app-0.1.0-SNAPSHOT.jar 

这不包括 Clojure 或任何依赖项。你想要:

java -jar ./target/app-0.1.0-SNAPSHOT-standalone.jar