ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Swift Package Manager 可编辑包(Editable Packages)机制全解析:SE-0082 设计详解与后续演进

Swift Package Manager 可编辑包(Editable Packages)机制全解析:SE-0082 设计详解与后续演进 文档【免费下载链接】swift-evolutionThis maintains proposals for changes and user-visible enhancements to the Swift Programming Language.项目地址https://gitcode.com/gh_mirrors/sw/swift-evolution点击查看免费下载本文以 SE-0082 提案原文 为核心骨架结合 swift-evolution 仓库中 SE-0149、SE-0175、SE-0201 等后续提案系统讲解 SwiftPM 如何从默认克隆到可见的Packages目录演进为隐藏源码 显式编辑模式以及swift package edit命令的设计动机、详细设计、不变量保证与历史演进路径。读完本文你将掌握可编辑依赖机制的前因后果、底层行为约定以及它如何演化为现代 SwiftPM 的本地依赖与Package.resolved协作模型。一、背景与动机两条几乎矛盾的工作流SE-0082作者 Daniel Dunbar评审经理 Anders Bertelrud状态为Implemented (Swift 3.1)开篇即指出 SwiftPM 需要同时支撑两种工作流而这两者天然存在张力确定性构建包管理器应当尽量保证构建行为的确定性使包的其他使用者或部署场景与开发者看到完全一致的行为。因此默认的依赖一致性模型应当很强——当开发者期望针对某个 tag 构建时包管理器要主动确保使用的是该 tag 对应的精确源码。如果开发者无意中针对被修改过的包进行构建而没有显式表达意图默认行为应当报错或警告。上游迭代开发许多项目同时掌控多个相互依赖的包例如应用 数个自研库需要在不打 tag 的情况下跨包协同开发也鼓励使用者把改动回馈给所依赖的包。这就要求包管理器允许开发者直接在依赖源码上工作。从源码结构看这一矛盾在当时的 SwiftPM 中体现得很直接旧实现总是把依赖源码检出到项目包旁边的Packages子目录目录名由包名 tag拼接而成例如Packages/Foo-1.2.3。用户虽然可以直接修改该目录中的源码并被构建拾取但对包作者来说这个目录通常不是他们希望编辑的规范位置更麻烦的是该位置的 git 仓库处于tag 上而 tag 并不是适合做迭代开发的状态。即使用户手动切换分支也会出现目录名内嵌 tag 与目录内容不一致的混淆。此外包管理器天然还要处理update这类与依赖源码交互的操作——直接支持用户编辑源码就要求包管理器回答如何处理用户意图与当前树内容冲突的棘手问题。二、核心方案两个支柱SE-0082 的解决思路由两条紧密关联的设计支柱构成支柱一隐藏默认检出位置。把依赖源码的默认检出位置改为隐藏作为实现细节存在默认构建总是精确使用依赖解析所选 tag 对应的源码。隐藏的理由很务实在一个成熟稳定的生态里一次构建会牵涉大量包其中大多数对当前项目开发者毫无兴趣——直接依赖的源码或许值得一看但依赖的依赖的源码对项目开发者而言就是实现细节。隐藏源码的代价是查看源码多了些步骤提案预期开发者能在--edit与结束编辑之间高效切换长期需求如查阅文档则由网页托管文档等其他机制解决并且该默认行为如果被证明有问题会重新评估。支柱二显式的编辑模式。新增swift build --edit PACKAGE把一个既有依赖转换为可编辑依赖editable dependency。一旦Packages中存在这样的可编辑包swift build将始终直接使用该目录中的精确源码进行构建——无论其处于什么状态、git 仓库状态如何、打了什么 tag、依赖解析期望哪个 tag。换言之它会直接就着现有源码构建。两条支柱各司其职隐藏源码让针对已知成熟库编程的常见场景减少干扰显式切换到可编辑模式则让针对规范版本集合构建与针对可能被修改的包构建两种状态之间的界限变得清晰可见。提案特别强调该功能被定义在swift build的行为层面而非 lockfile / 包固定pinning机制——因为用可编辑版本还是规范解析版本最终是个体开发者的个人决定。团队协作场景如一组开发者共同编辑同一批包当时尚无明确特性支撑但设计上预留了演进空间。三、详细设计七个具体步骤3.1 隐藏克隆位置与--get-package-path提案第一步是把包克隆移入既有的.build目录同时新增显式命令swift build --get-package-path PACKAGE以受支持的方式查询包路径。这样设计的好处是未来若希望把缓存透明地迁移到共享位置用户代码不会因此失效。需要明确的是该命令在提案阶段是受支持的方式意在替代用户对包路径的隐式假设。3.2Packages目录的替换语义解析包图时SwiftPM 会加载Packages目录中存在的所有仓库将其作为包图中同名包的替换。关键细节初始阶段不审计仓库来源repository origin——这允许开发者开发尚未推送到任何服务器的包图例如本地新建、还没建远端仓库的项目。当可编辑包存在时它会被用来满足依赖图中该包的所有实例依赖图中的包可以全部、部分或完全不进入编辑状态没有任何限制。3.3 仅从根包加载提案明确规定不从根包以外的任何包加载可编辑包——即除根包外其他地方出现的Packages目录将被忽略。这一约束保证了可编辑行为只由当前项目的根包控制避免传递依赖中的同名目录引发意外覆盖。3.4--edit NAME与核心不变量新增--edit NAME子命令提案原文写作swift build --edit最终落地为swift package edit。约束为被编辑的包必须是包图中已存在的包。行为是取出依赖解析本应选择的那个精确 tag把该仓库克隆到Packages/NAME并检出到该 tag。该设计追求的核心不变量是从没有任何可编辑依赖的初始状态出发执行下面三个连续命令每一步的构建结果必须完全一致swift build swift build --edit NAME swift build即进入编辑模式本身不应该改变构建产物——它只是把原本会从隐藏位置按 tag 检出的源码换成显式放置在Packages/NAME的同一份 tag 源码。开发者随后对Packages/NAME的修改才会影响后续构建。3.5--end-edit NAME结束编辑初版延迟实现提案计划引入--end-edit NAME确切名称当时标注为 TBD最终落地为swift package unedit让包管理器恢复使用规范解析的包。实现上需要删除Packages/NAME检出这是需要格外谨慎的操作——但同时这也是向用户传达编辑中的仓库尚未推回规范解析包的好时机例如改动未提交、未推送、未打 tag。提案明确表示该特性大概率从初始实现中推迟并建议用户在特性到来前用rm -rf Packages/NAME手工结束编辑。这条临时方案也解释了为什么历史上 Swift 文档中一直保留着手工删除Packages目录的说明。3.6 可选的元数据文件提案考虑引入一个元数据文件记录项目状态与哪些包处于可编辑状态。其价值有二提供更好的诊断信息记录可编辑包的替代位置——当作者在文件系统规范位置同时维护多个独立项目、并希望其他包引用它做迭代开发时非常有用。在引入该文件之前这一行为可用Packages目录内的符号链接symbolic link模拟后续 SE-0149 正是把这一设想正式化。设计上还有一个原则性决定若引入该文件文件系统中可编辑包的表现形式永远是权威数据源元数据文件只用于补充无法从文件系统推断的诊断或信息绝不允许二者产生主从倒置。3.7--edit-all一键全量编辑提案还考虑提供swift build --edit-all标志一次性把所有包切换到编辑模式。这一设想同样服务于同时开发多个自己掌控的包的场景属于可选增强。四、为什么不用 lockfile / pinning 语义实现提案在 Alternatives 一节专门讨论了借助包固定/lockfile 机制承载迭代开发工作流的路线。结论是本提案的动机部分正源于在既有Packages目录语义之上精确定义 package pinning 语义的困难。把编辑哪个包的决定放在swift build行为层面而非解析机制层面是因为它是开发者个人工作流选择不应与团队共享的依赖解析状态耦合。五、为未来扩展预留的空间SE-0082 明确指出可编辑特性为后续工作流行为提供了新的挂载点并列举了三个方向其中部分被后续提案逐一兑现推断下一个语义版本允许用户指定或自动推断可编辑包的下一个语义版本然后仿佛该包已打上这个 tag地构建整个包图从而保证本地构建结果与将来提交、打 tag 后的结果一致。安全退出编辑模式提供带安全检查的退出机制例如校验改动已提交、已推送、已打 tag。元数据变更告警当可编辑包的项目元数据如依赖 tag 声明发生变化时通知开发者——因为处于编辑状态时这些改动不会被构建反映出来静默接受极易误导。六、对现有包的影响与迁移考量这是对既有包检出行为的实质性变更老项目遗留的Packages目录内含大量带 tag 名字的克隆会被新版本swift build视为一堆名字匹配不到依赖图的编辑包。提案建议通过过渡机制检测并警告这种情况甚至由此催生了在包管理器内记录项目最后一次使用的工具版本、以便自动启用迁移行为的想法——这与后来 Swift tools-version 机制manifest 头部// swift-tools-version:声明的思路一脉相承后者正是 SwiftPM 管理行为迁移的标准手段。七、备选方案与设计取舍提案还记录了两个方向的取舍讨论是否应该默认隐藏源码支持方认为成熟生态中依赖众多且大多无趣隐藏可减少干扰反对方认为增加了查看源码的额外门槛。提案的折中是--edit与结束编辑之间高效切换 网页文档等替代机制并明确保留将来更改默认行为的灵活性。是否用元数据驱动如上文 3.6 所述文件系统始终是权威元数据只做诊断增强。八、演进与落地从 SE-0082 到现代 SwiftPMSE-0082 于 Swift 3.1 落地后可编辑包机制在后续提案中持续演进从仓库中的后续提案可以清晰看到这条脉络SE-0149: 支持 Top of Tree 开发Swift 4.0把swift package edit扩展出可选--path参数允许开发者把自己管理的既有检出作为覆盖override例如swift package edit bar --path ../bar。其行为与 SE-0082 3.6 节的设想完全对应./Packages/bar变成指向给定路径的符号链接映射记录在工作区workspace中swift package unedit只删除符号链接而不删除用户自己的检出若给定位置没有检出包管理器会代劳首次克隆。SE-0175: 修订依赖解析Swift 4.0明确了 edit 与解析命令的交互——swift package edit会隐式调用swift package resolve但即使 resolve 失败、只要已识别并拉取到同名包仍允许进入编辑可用于修复不可解析的依赖图swift package unedit则是先解除编辑再执行 resolve。同时处于编辑态的依赖允许与Package.resolved中记录的版本不一致编辑中的包版本不会被自动改写执行swift package update时编辑中包及其依赖子树下所有包的解析版本会从 resolved 文件中移除避免记录下离开编辑模式后根本无法复现的版本组合。SE-0201: 本地依赖Swift 4.2提供Package.Dependency.package(path:)声明式本地依赖直接用磁盘路径替代 git URL包管理器不对本地包执行任何 git 操作本地依赖会覆盖包图中同名依赖、不写入Package.resolved与编辑模式行为一致且不允许对本地依赖再使用编辑特性。该提案的动机部分明确提到此前多个关联包协同开发需要为每个依赖手工执行swift package edit这正是 SE-0082 引入的工作流而本地依赖把这一摩擦进一步降低。九、要点回顾设计决策SE-0082 内容后续演进默认检出位置从可见Packages/Name-tag移入.build实现细节保留至今可用--get-package-path查询编辑入口swift build --edit PACKAGEswift package editSE-0149 增加--path结束编辑--end-edit延迟临时用rm -rf Packages/NAMEswift package unedit与 resolve 联动覆盖语义按包名替换不审计 origin仅根包生效SE-0201 本地依赖沿用同名覆盖与解析状态的关系编辑决定属于个人工作流不进 lockfileSE-0175 规范了与Package.resolved的交互一言以蔽之SE-0082 奠定了 SwiftPM 处理依赖源码归属权的基石——默认把依赖源码当作不可改动的构建输入把修改依赖变成一种需要显式声明的、受控的工作流状态并用进入编辑不改变构建结果这一不变量保证两种模式之间无缝切换。理解这份提案也就理解了今天swift package edit、unedit、Package.resolved与本地依赖等现代工作流为何如此设计。赞分享文档【免费下载链接】swift-evolutionThis maintains proposals for changes and user-visible enhancements to the Swift Programming Language.项目地址https://gitcode.com/gh_mirrors/sw/swift-evolution点击查看免费下载相关推荐5步掌握Teable无代码数据库从Excel到智能业务系统5步掌握Teable无代码数据库从Excel到智能业务系统 你是否还在为数据管理发愁Excel表格越来越臃肿传统数据库又太复杂难懂。现在Teable无代文档Swift 增强浮点协议全解析SE-0067 中 FloatingPoint 与 BinaryFloatingPoint 的设计、实现与后续演进Swift 增强浮点协议全解析SE 0067 中 FloatingPoint 与 BinaryFloatingPoint 的设计、实现与后续演进 本文以 pr文档深入解读 Swift Evolution SE-0018灵活成员逐项初始化Flexible Memberwise Initialization的设计与后续演进深入解读 Swift Evolution SE 0018灵活成员逐项初始化Flexible Memberwise Initialization的设计与后续文档创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表