2024 年 Clojure 状态调查! 中分享您的想法。

欢迎!请查看 关于 页面了解有关此操作的信息。

+46
工具依赖
重新标记

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

一种使用情况是有时只针对一个项目进行开发,而有时则针对一组项目进行开发。

这里有一个例子

{: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 单仓库的简单而强大的结构。当然,有相当多的方法可以对付这个问题,但一个简单的方法是

  • 在仓库根目录下维护一个单一的 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和运维协同工作得很好,因为它阻止了在添加别名时需要更新大量脚本,例如(即您可以在任何地方始终使用相同的“main”别名并添加/删除它所要求的别名,这对外部来说是无形的)。
我们有一个单一代码仓库,这确实是我们遇到的一个痛点,直到我们在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学习中学到的关键一点是避免这些方法,而使用组合,这样可以提供更大的灵活性。

使用 tools.build 是否能更容易地解决 mono-repos 中的这个问题?

在原始问题提出的事例中,是否有机制来防范或至少警告 :dev/project1 包含了 :dev/all-projects 或其他集结别名的情况?这个分组可以有多少层级?

是否有明确先决规则?
是否有工具可以诊断冲突所在 - 也许 -Stree 足够,但我不确定

别名分组是否仅限于在项目 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 的别名组合在一起时,只有最后一个会被使用(因为 main opts 是有位置关系的,传递给 clojure.main 的 -main 函数),所以你不能通过单个命令行运行多个代码检查工具,即使有多个别名也是如此。

你需要其他进程依次运行这三个代码检查工具的 -main 函数。
是的,这是一个众所周知的问题,但仍然可以通过在 :lint 别名内提供一些自定义的 :main-opts 来克服这个问题,例如按照 Cam Saul 的 Lein-alike 语法示例。这样,它将是最后一个,并将覆盖其他所有选项。
Mark,你的意思是有否包含"-e"的:main-opts,以及一个程序性地调用三个主要函数的表达式?就像 "(do (eastwood/-main) (kibit/-main) (antq/-main))"
(无论主命名空间是什么)。

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