☰
Leiningen 版本变更历史全解析:从 0.5.0 到 2.11.2 的功能演进与工程实践
2026/9/28 2:52:48 网站建设 项目流程
  • 构建工具
  • CLI

【免费下载链接】leiningen

Moved to Codeberg; this is a temporary convenience mirror

项目地址:https://gitcode.com/gh_mirrors/le/leiningen
点击查看免费下载

本文以官方NEWS.md变更日志为骨架,系统梳理 Clojure 构建工具 Leiningen 自 2009 年首发(0.5.0)到 2024 年 2 月(2.11.2)的全部用户可见变更,逐版本解读核心功能、任务、配置项与关键 Bug 修复,并结合当前仓库源码(src/leiningen、leiningen-core/src/leiningen/core与test目录)给出实现层面的佐证。读完本文,你将获得一张完整的 Leiningen 能力地图:既知道每个版本"改了什么",也知道这些机制在源码里如何落地,可直接用于项目升级评估、project.clj配置决策与迁移排障。

一、版本脉络总览:两个大版本时代

Leiningen 的变更历史可以清晰地划分为两个时代:

  • 1.x 时代(2009–2012):从 1.0.0 的隔离类加载器与独立project.clj模型起步,逐步引入 checkout 依赖、new任务、install/deploy/search/retest等核心任务,以及在 1.6.0 时代奠定的 Maven 仓库(~/.m2)构建 classpath 的架构。
  • 2.x 时代(2012 至今):以 2012 年 3 月的2.0.0-preview1为分水岭,leiningen-core被拆分为独立库、Pomegranate 取代 maven-ant-tasks、构建产物迁入target/、全面引入profiles(配置档)机制。2.0 正式版于 2013-01-19 发布,此后直至 2024-02-13 的 2.11.2,功能演进围绕 nREPL 集成、deps诊断、release/vcs自动化、uberjar 加固、XDG 规范支持等方向持续展开。

当前仓库project.clj中标明的版本为2.11.3-SNAPSHOT,即 NEWS.md 中 2.11.2 之后的开发中版本,可作为"历史尽头"的参照点。

二、1.x 时代:从 0.5.0 到 1.7.1 的奠基与成型

2.1 早期基础(0.5.0 – 1.0.1)

  • 0.5.0(2009-11-17):Leiningen 的首次发布。

  • 1.0.0(2009-12-05):确立了现代 Leiningen 的基本骨架,包括:

    • project.clj中可配置 source、test、compilation 路径;
    • 隔离类加载器——项目代码可以在与 Leiningen 自身不同版本的 Clojure 下编译/测试;
    • 新增new任务生成空项目;install任务不再要求本机装有 Maven;
    • 按 .class 与 .clj 时间戳判断是否重新 AOT 编译;
    • jar 内置pom.xml、pom.properties及更详细的 manifest,并生成$PROJECT-standalone.jar;
    • 新增resources/目录进入 classpath 与生成的 jar;
    • 使用-Xbootclasspath加快启动。
  • 1.1.0(2010-02-16):新增lein upgrade任务、exclusions依赖排除支持、原生依赖支持、Windows 实验性支持;只有当确实需要时才下载 SNAPSHOT 版本。

  • 1.2.0(2010-07-18):大量可用性改进——classpath命令、:aot别名、:jvm-opts与:warn-on-reflection、checkout 依赖(Checkout Dependencies)、密码保护仓库、:jar-name/:uberjar-name定制、test-resources 目录、为uberjar自动 clean、defproject中支持 unquote 等。

  • 1.3.0(2010-08-19):新增:omit-source、交互式interactive任务、test!任务、~/.lein/init.clj启动脚本、~/.lein/plugins用户级插件、多任务命令行链式执行,并将启动脚本切换为/bin/sh。

  • 1.4.0(2010-12-02):合并了来自独立插件的run任务与javac任务;新增:repl-options、uberjar-exclusions、测试选择器(test selectors)谓词、plugin任务;eval-in-project引入 init 参数以应对著名的Gilardi Scenario。

  • 1.5.0(2011-03-22):新增deploy任务;按仓库粒度支持:update/:checksum策略;全局:exclusions;:min-lein-version使旧版 lein 用户得到明确警告。

  • 1.6.0(2011-06-29):新增trampoline任务、retest任务、search任务、原生依赖支持;classpath 直接基于~/.m2构造。

  • 1.7.0(2012-02-06):允许任意任务执行 trampoline;LEIN_JAVA_CMD/LEIN_JVM_OPTS与JVM_OPTS分离;支持项目内:plugins;64 位 JVM 上的分层编译(tiered compilation)加速启动。

2.2 1.x 遗产与 2.0 的替代关系

1.x 中引入的若干机制(:dev-dependencies、plugin任务、:extra-classpath-dirs、隐式 AOT 等)在 2.0 中被逐一替换或废除——project.clj中今日见到的:profiles、:middleware、:aliases、:eval-in等全部来自 2.0 重写。

三、2.0.0 系列:架构重写的里程碑(2012–2013)

3.1 从 preview1 到 preview10 的关键决策

2.0.0-preview1(2012-03-07)开启了代号式的架构改造,多数决策沿用至今:

  • 拆分leiningen-core为独立库:核心逻辑可从主程序分离,供插件与第三方复用,对应仓库中的leiningen-core/src/leiningen/core/目录(project.clj、classpath.clj、eval.clj、main.clj等)。
  • 用 Pomegranate 库取代 maven-ant-tasks:依赖解析直接面向 Aether API,~/.m2成为本地仓库的默认来源。
  • 构建产物迁入target/:source-paths/test-paths/resource-paths改为复数形式;AOT、javac、uberjar 的输出集中管理,profile 隔离的 target 目录在 2.3.0 中进一步细化。
  • profiles 机制::dev、:user、:default、:provided、:offline、:base等内建 profile 建立,:dev-dependencies被:devprofile 取代;2.0.0 正式版中:userprofile 在项目外也可作为项目 map 使用。

后续 preview 版本持续补全能力:

  • preview3:offline profile、deps任务显示依赖树、连接 nrepl server、:connectHTTP nREPL 支持、:filespecs、$http_proxy支持。
  • preview4:-o(offline)与-U(强制更新快照)命令行别名、pom.xml回到项目根目录、checkout 依赖不进入 production profile。
  • preview5:GPG 加密部署凭据、deploy 凭据提示、默认拒绝 checksum 不匹配的下载 jar。
  • preview6:环境变量仓库凭据、自定义 SSL:certificates、Clojars 证书默认内置。
  • preview7:lein deps :verify验证依赖签名、任务别名可遮蔽内建任务、:mirrors支持、do任务接管任务链式执行。
  • preview8:TERM=dumb支持、nREPL handlers/middleware 可从项目配置读取、:prep-tasks可携带参数。
  • preview9:providedprofile 默认用于除 uberjar 外的所有场景、$LEIN_FAST_TRAMPOLINE缓存 trampoline 命令、HTTPS 代理、leinrc文件。
  • preview10:repl 默认监听127.0.0.1解决 IPv6 问题。

3.2 2.0.0 正式版与 2.1–2.3 的增量

  • 2.0.0(2013-01-19):接受:main作为run任务的-m别名;修正 repl 的 reader 问题;项目外运行体验完善。
  • 2.1.0(2013-03-19):新增update-in任务(对项目 map 任意位置做函数式修改)、~/.lein/profiles.d支持、:eval-in :nrepl实验支持、系统级 profiles、deploy 凭据命令行传入、带 classifier 的 jar 构建、:mirrors用于 jar/uberjar、compile任务接受正则参数。其中update-in在仓库中由 update_in.clj 实现。
  • 2.1.2/2.1.3:update-in支持顶层 key 与 profile;别名可携带 docstring;trampolined repl 挂起修复。
  • 2.2.0(2013-05-28):引入:uberjarprofile、:java-agents、profile 间 target 目录隔离、递归 checkout 依赖、部署 ad-hoc 文件。
  • 2.3.0(2013-08-08):新增:clean-targets(可清理额外目录)、:eval-in :pprint、:compile-path/:native-path按 profile 作用域化、:pedantic支持在版本解析歧义时中止。
  • 2.3.3/2.3.4:uberjar-merge-with支持;写入.nrepl-port文件便于工具互操作;deps相关告警建议:exclusions;pom-plugins增强。

仓库 project.clj 中defaultsmap(约 220–253 行)保留了这些 2.x 配置的现代形态,例如:

:release-tasks ^:top-displace [["vcs" "assert-committed"] ["change" "version" "leiningen.release/bump-version" "release"] ["vcs" "commit"] ["vcs" "tag"] ["deploy"] ["change" "version" "leiningen.release/bump-version"] ["vcs" "commit"] ["vcs" "push"]] :pedantic? ^:top-displace ranges :uberjar-exclusions [#"(?i)^META-INF/[^/]*\.(SF|RSA|DSA)$" #"^module-info.class$"]

这印证了 2.4.0 引入的release/vcs任务链、2.5.0 引入的 pedantic 默认策略,以及 2.9.9 对module-info.class的排除,都是沉淀在默认项目配置中的第一类公民。

四、2.4–2.7:发布自动化、管理依赖与 Windows 生态

4.1 2.4.x:release、vcs、change 三大自动化任务登场

  • 2.4.0(2014-06-09):新增release任务(自动化常见发布步骤)、vcs任务(版本控制自动化)、change任务(程序化改写project.clj);别名可从项目 map 拼接值;插件可覆盖内建任务;deploy前自动clean避免库中残留 AOT;LEIN_SILENT抑制*info*输出;new支持--force作用于已存在目录。

change任务在仓库 change.clj 中有完整实现,其 docstring 给出了三种典型用法:

# 给当前版本追加 -SNAPSHOT 后缀 $ lein change version str '"-SNAPSHOT"' # 用 set 直接覆盖版本 $ lein change version set '"1.0.0"' # 修改 :dependencies 中某个依赖的版本 $ lein change :dependencies:org.clojure/clojure set '"1.10.1"'

实现上,change不读取合并后的项目 map,而是用net.cgrand.sjacket解析器直接操作磁盘上的project.clj文本(change-string函数负责将字符串参数转成 Clojure 数据并走 zip 遍历改写),以保留原文件的注释与排版。2.9.9 中"允许change编辑依赖版本"即对应find-dependency-version对:dependencies/:managed-dependencies向量的处理。

  • 2.4.1/2.4.3:vcs commit不提交未跟踪文件;mirrors可配置修复;pom.properties暴露版本号;LEIN_NO_USER_PROFILES跳过用户 profile;vcs tag 支持前缀。

4.2 2.5.x:profile 语义深化

  • 2.5.0(2014-09-14):^:leakyprofile 可影响下游项目;profile 可从插件加载;leiningen.core.project/read负责初始化项目并合并默认 profiles。
  • 2.5.1–2.5.3:lein clean清理所有 profile 的 target;profile 合并保持声明顺序;update-in可使用未 require 的函数;多:replprofile;lein retest记录失败测试信息;lein release尊重 git 的退出码。javac错误打印到终端的修复,与仓库 javac.clj 及对应测试test/leiningen/test/javac.clj的行为一致。

4.3 2.6–2.7:托管依赖与生态支撑

  • 2.6.0(2016-02-05):模板、repl 与 Leiningen 自身升级到 Clojure 1.8;放弃 Clojure 1.1 及更早版本支持。
  • 2.7.0(2016-08-24):新增:managed-dependencies支持;lein test前执行:prep-tasks以覆盖生成式测试命名空间;Windows PowerShell 脚本;:scm :dir尊重;fixture 错误捕获;私有仓库在 jar/uberjar/deploy 中保留。

:managed-dependencies的引入与仓库中的测试项目一一对应:test_projects/managed-deps/、test_projects/managed-deps-snapshot/,并在test/leiningen/test/中有配套测试。2.7.1 进一步放宽:托管依赖中版本不要求非nil,且快照依赖可正常解析。

五、2.8–2.9:nREPL 升级、deps 诊断与安全加固

5.1 2.8.x:nREPL 0.5 切换与 Java 9 兼容

  • 2.8.0-RC1/2.8.0(2017-09/10):deps新增:query(快速查找最新版本)、:why(追踪单个依赖的来源)、:plugin-tree/:tree-data子任务;search任务改为直接调用在线 API 而非下载索引;默认要求远程仓库走 TLS;$CLASSPATH被设置时给出警告;LEIN_USE_BOOTCLASSPATH支持;vcs可自定义提交信息、可跳过签名 tag;移除 clj-http 与 cheshire 依赖以降低冲突;Java 9 兼容(禁用字节码校验、跳过 bootclasspath)。
  • 2.8.1(2017-10-27):lein help在 Java 9 下列出内建任务;包管理器安装的 lein 不再吞掉退出码。
  • 2.8.2(2018-12-11):诊断信息统一走 stderr;pprint新增--not-pretty;jar 元数据加入项目坐标;:pom-plugin自由配置。
  • 2.8.3(2018-12-14):移除损坏的无人值守 GPG 部署特性;repl使用:main作为初始命名空间。

2.8.2 的"切换 nREPL 0.5"标记为Breaking,官方建议遇到lein repl问题时参考升级说明。当前仓库 project.clj 依赖[nrepl "1.0.0"],对应 2.10.0 的 nREPL 1.0.0 升级。

5.2 2.9.x:性能、病态依赖树与 XDG 规范

2.9 系列密集修复了深层依赖树的栈溢出、无限循环、重复告警等问题,并带来一批用户可感知的增强:

  • 2.9.0(2019-02-10):默认重新启用 bootclasspath 优化;AOT 命名空间排序一致化;插件与新模板项目使用 Clojure 1.10.0。
  • 2.9.2(2020-02-28):self-install 过程增加 checksum 校验;验证依赖时携带仓库认证;pom.xml包含project.clj中的:repositories。
  • 2.9.4(2020-07-08):测试选择器跳过非测试 var;deps :query结果修正;nREPL 0.7;REPL-y 支持 scheme 配置。
  • 2.9.6(2021-04-15):模板查找适配 Clojars 新 group 规则;非 nrepl 连接时不执行:reload。
  • 2.9.7(2021-09-15):检测病态依赖树并告警;Clojure 1.10.3;对指向单一版本的版本范围不再告警;部署失败时错误信息更清晰。
  • 2.9.8(2021-11-11):修复深层依赖树栈溢出;LEIN_JAR可被覆盖以支持自定义安装位置。
  • 2.9.9(2022-08-05):仓库从 GitHub 迁往 Codeberg;new模板 group-id 修复;Java 9 模板列表兼容;pedantic 无限循环修复;uberjar 排除module-info.class;repl 支持通过:headless :socket PATH绑定文件系统 socket。
  • 2.9.10(2022-08-09):dev-resources 不再泄漏进 jar/uberjar;XML 解析避免非法反射访问。

:pedantic的默认行为在 project.clj 中为(quote ^:top-displace ranges),即默认对版本范围给出警告;pedantic.clj及其测试(leiningen-core/test/leiningen/core/test/pedantic.clj)承载冲突检测逻辑。

六、2.10–2.11:nREPL 1.0、SSH 签名与静态分析

6.1 2.10.0(2022-12-09)

  • 升级到nREPL 1.0.0(与当前仓库project.clj的依赖一致);
  • :eval-in :leiningen不再吞掉测试退出码;
  • 部署文件可使用SSH 密钥签名(不再局限于 GPG);
  • uberjar 向 target 路径拼接 profile 的错误修复。

6.2 2.11.x(2023–2024)

  • 2.11.0(2024-01-27):
    • 顶层:exclusions可影响顶层:dependencies;
    • :eval-in :nrepl的正在运行 repl 检测与崩溃修复;
    • jar 构建期间测试路径文件可见性修复;
    • check在依赖 AOT 的命名空间上的问题修复;
    • 新增static-classpath任务(面向静态分析);
    • 病态依赖树处理性能大幅提升;
    • search 失败错误报告改进;
    • 支持 XDG 配置目录,且 self-install 优先使用$XDG_CACHE_HOME;
    • 对有缺陷的 composite profile 给出警告。
  • 2.11.1(2024-01-28):修复从控制台读取密码进行部署时的 Bug。
  • 2.11.2(2024-02-13):新增:preserve-eval-meta配置以避免项目代码反射。

6.3 源码佐证:static-classpath 与 preserve-eval-meta

static-classpath任务(static_classpath.clj)的设计目标是不加载任何插件或项目代码的前提下输出 classpath,因此"可在不可信项目上安全运行"。其实现要点:

  • unsafe-keys(:plugins、:hooks、:middleware、:certificates、:mirrors、:local-repo、:implicits等)在读取project.clj后被dissoc掉,避免触发副作用;
  • 只合并:base :system :provided :dev四个安全 profile;
  • docstring 明确"可能不如classpath精确,但适合静态分析场景"。

对应测试 static_classpath.clj 验证了该任务可通过main/-main "static-classpath"直接调用。

:preserve-eval-meta(2.11.2 新增)解决的是lein run场景下的反射警告问题:默认情况下,注入项目进程执行的代码会被去掉元数据(包括类型提示),因为部分插件会携带无法被 reader 读取的元数据对象(如#object标签);但在开启:global-vars {*warn-on-reflection* true}的项目中,缺少类型提示会导致lein run打印反射警告。设置:preserve-eval-meta true后,eval.clj 会以*print-meta*打印待求值代码(见 246–250、335、366 行附近),从而保留类型提示。测试test/leiningen/test/run.clj的test-preserve-eval-meta用例断言:默认项目出现Reflection warning,而preserve-eval-meta测试项目(test_projects/preserve-eval-meta/)不出现该警告。

七、贯穿版本的关键机制速查

机制引入版本核心作用当前实现位置
profiles2.0.0-preview1按场景组合项目配置project.clj(merge-profiles等)
:eval-in2.0.0 系列控制项目代码执行方式(:leiningen/:nrepl/:classloader等)eval.clj
:pedantic2.3.0 / 2.5.0依赖冲突检查策略pedantic.clj
change/update-in2.4.0 / 2.1.0程序化改写project.cljchange.clj、update_in.clj
release/vcs2.4.0发布流程与版本控制自动化release.clj、vcs.clj
:managed-dependencies2.7.0BOM 式托管依赖test_projects/managed-deps/等测试项目
deps :query/:why2.8.0依赖版本查询与来源追踪deps.clj
static-classpath2.11.0不加载代码的安全 classpath 输出static_classpath.clj
:preserve-eval-meta2.11.2保留注入代码的元数据避免反射eval.clj

八、实践建议:从变更历史反推升级与配置决策

  1. 升级评估:2.8.2 的 nREPL 0.5 是 2.x 时代唯一的明确 Breaking 变更;若长期停留在 2.7.x,应先核对lein repl相关插件兼容性(参见 PLUGINS.md 与 FAQ.md)。2.9.9 起仓库迁移至 Codeberg,域名类外部链接请以官方仓库为准。
  2. 依赖诊断优先用deps :why:遇到"多余依赖"或版本冲突,lein deps :why group/artifact可快速定位来源,替代手工翻 POM。
  3. 静态分析场景:在不可信或 CI 沙箱中获取 classpath,优先lein static-classpath而非lein classpath,前者不加载插件与项目代码(源码证据见 static_classpath.clj 的unsafe-keys与 docstring)。
  4. 反射警告治理:若项目开启全局*warn-on-reflection*且lein run出现"can't be resolved"类反射警告,可设置:preserve-eval-meta true;但需注意这会破坏携带不可读元数据的插件的兼容性(这正是 2.11.2 之前默认不保留元数据的原因,测试注释见 run.clj)。
  5. 发布自动化:lein release默认任务链(vcs assert-committed→ 版本 bump → 提交 → tag → deploy → 再 bump → 提交 → push)可直接在project.clj中通过:release-tasks定制,模板见 project.clj 的defaults。
  6. XDG 环境:2.11.0 起 Leiningen 支持 XDG 配置目录,self-install 会优先使用$XDG_CACHE_HOME,符合 freedesktop 规范的环境无需再手工迁移~/.lein与~/.m2。

九、结论

从 2009 年的 0.5.0 到 2024 年的 2.11.2,Leiningen 的每一步变更都沉淀在NEWS.md的条目中,并在当前仓库的源码与测试里留有可验证的实现痕迹。这张版本地图既是升级迁移的路线图,也是理解project.clj各配置项由来的索引:profiles、:pedantic、:managed-dependencies、deps :why、static-classpath、:preserve-eval-meta……每个键与任务背后,都有一段可追溯的功能演进史。如需完整条目,请直接查阅仓库根目录下的 NEWS.md;配置细节可对照 sample.project.clj 与 TUTORIAL.md。

  • 构建工具
  • CLI

【免费下载链接】leiningen

Moved to Codeberg; this is a temporary convenience mirror

项目地址:https://gitcode.com/gh_mirrors/le/leiningen
点击查看免费下载
上一篇:Awesome-CV会议演讲视频链接:增强经历可信度
下一篇:从共振峰合成到多语言支持:深度解析eSpeak NG的架构设计与实战应用

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询