2024 年 Clojure 状态调查中分享您的观点!

欢迎!请查看关于页面获取有关该功能的更多信息。

+46
tools.deps
重新标记

拥有一个能够启用其他别名的别名会有用。

一个用例是有时仅针对一个项目进行开发,但有时针对一组项目进行开发。

这里有一个例子:

{:aliases 
  {:dev/project1 {:override-deps {:local/root "/some/path/project1"}}
   :dev/project2 {:override-deps {:local/root "/some/path/project2"}}
   :dev/project3 {:override-deps {:local/root "/some/path/project3"}}
   ;; something like the following:
   :dev/all-projects {:aliases #{:dev/project1 :dev/project2 :dev/project3}}}

6 个答案

+2

(在 Slack 讨论中询问状态https://clojure.atlassian.net/browse/CLJ-2638之后)

最初,可能觉得需要其他别名的别名的想法不是很有用,但我认为它是组织 Clojure 单一仓库的一种简单而强大的结构。当然,有相当多的方式来应对 Clojure 单一仓库的问题,但直接的方法是

  • 在仓库根目录中维护一个单独的deps.edn文件。
  • 每个外部依赖一个别名。
  • 每个内部“模块”和关注点(如:foo/main:foo/test:bar/main:bar/test等)一个别名。

这就给了我们

  • 所有内容都清晰地在deps.edn
  • 无需动态构建 deps.edn 文件,如一些项目中所见(违背了声明性工具的目的)
  • 外部依赖项被锁定;例如,所有需要外部库的模块都使用相同的版本,而不会通过为该库使用专门的别名来重复使用
  • 构建所需的确切类路径非常简单;只需连接别名即可
  • 不存在诸如传递性本地依赖项未更新这样的情况
  • 不会有使用 ../../local-lib/src 路径这类不道德的做法

这是一种非常精确的方法,而且很管用。唯一的缺点是,你现在不得不与许多别名打交道,而且并不总是明显知道真正需要什么或不需要什么

clj -M:module-1/dev:module-1:main:module-2/main:ext/lib-1:ext/lib-2:ext/lib-3...
当然,你可以编写需要大量别名的脚本,但这既复杂又容易出错。如果别名能够要求别名的向量,这个问题就解决了。

另一个好处是,它与 CI 和 ops 兼容性良好,因为它防止了在添加别名时需要更新大量脚本(例如,您始终可以在任何地方使用相同的“main”别名并添加/删除所需的别名,外部对 `deps.edn` 不可见)。
我们有一个单一代码库,这是一个痛点之一,直到我们找到了一个更适合 deps.edn 的结构——参见 corfield.org 上关于这段旅程的一系列博文,我们现在正在迁移到 Polylith,这只需要几个别名。话虽如此,我自己的开发环境依赖于如下这样的调用

SOCKET_REPL_PORT=5000 clojure -J-Dlog4j2.configurationFile=log4j2-sean.properties -M:rebel:portal:everything:dev:test:runner:build:add-libs:dev/repl

当然,能够将所有这些都包装在一个单独的 :dev/sean 别名中会很好(我通常会为某些任务添加更多的别名到该列表中)。
+1

感谢John Stevenson指出,从多个别名继承时存在潜在冲突。因此,使用别名向量而不是集合来引用可能更可取。由此产生的其他设计挑战需要解决,但我仍然认为这是一项有用的功能。

是的,顺序确实很重要
+1

我的顾虑是将继承(甚至是多重继承)的复杂性引入本已简单的配置中。从多年的Java编程中,我学到的关键一点是避免这些方法,而使用组合(composition),这提供了更大的灵活性。

使用 tools.build 是否是解决 mono-repos 问题的更简单方法?

在原始问题的示例中,是否有一种机制来防范或者至少警告:dev/project1包含:dev/all-projects或另一个将别名分组在一起的别名的情况?这种分组可以深入到多少层?

是否有明确的前置规则?
是否有工具可以诊断冲突在哪里 - 可能是 -Stree 足够了,但我并不确定

别名分组将被限制在 project deps.edn 中定义的别名,还是会包含用户级别的 deps.edn(我假设排除用户级别配置将增加更多复杂性)

或许有一种避免这种情况的方法,比如有一个像 :meta-aliases 这样的东西,它可以只包含别名,而不包含其他 :meta-aliases,但这样似乎还是在增加复杂性。

我希望能解决与 mono-repls 相关的特殊问题,而不会给 deps.edn 配置增加复杂性(尤其是避免继承或多重继承)。

+1

我认为可能的语法可能类似于 Leiningen 所做的

{:aliases
 {:with-tests {:extra-paths ["test"]}
  :with-dev-deps {:extra-deps [...]}
  :dev [:with-test :with-dev-deps {:exec-fn some/fn}]}}

:aliases 里面的别名可以是像我们已支持的普通映射,或者是一个由带有名称的别名组成的向量,后面可以跟着一个映射。别名向量本身可以简单地理解为包含了这些别名,例如上面例子中的 dev 别名实际上相当于 with-tests:with-dev-deps:dev (使用 dev 的映射部分)

0
0

这对于代码审查非常有用。

clj -M:eastwood:kibit:antq

可以是

clj -M:lint
当你组合包含 :main-opts 的所有别名时,只使用最后一个(因为主选项是定位的,传递给 clojure.main 的 -main 函数),因此你无法通过单个命令行一次性运行多个代码审查工具,即使有多个别名。

你需要其他进程依次运行三个代码审查工具的 -main 函数。
是的,这是一个已知问题,但仍然可以通过在 :lint 别名内部提供手工定制的 :main-opts 来解决,将所有工具的主要 fn 调用组合成一个。例如,按照 Cam Saul 的 Lein-alike 语法示例。这样,它将是最后一个,并且应覆盖其余部分。
by
马 克,你的意思是拥有 :main-opts 包含 "-e" 和表达式,程序性地调用三个 -main 函数中的每一个吗?比如 "(do (eastwood/-main) (kibit/-main) (antq/-main))"。
无论主命名空间是什么。

鉴于许多工具在末尾调用 (shutdown-agents),你可能无法在之后运行 -main 函数...
...