機(jī)制全解析:SE-0082 設(shè)計(jì)詳解與后續(xù)演進(jìn))
文檔【免費(fèi)下載鏈接】swift-evolutionThis maintains proposals for changes and user-visible enhancements to the Swift Programming Language.項(xiàng)目地址https://gitcode.com/gh_mirrors/sw/swift-evolution點(diǎn)擊查看免費(fèi)下載本文以 SE-0082 提案原文 為核心骨架結(jié)合 swift-evolution 倉庫中 SE-0149、SE-0175、SE-0201 等后續(xù)提案系統(tǒng)講解 SwiftPM 如何從默認(rèn)克隆到可見的Packages目錄演進(jìn)為隱藏源碼 顯式編輯模式以及swift package edit命令的設(shè)計(jì)動機(jī)、詳細(xì)設(shè)計(jì)、不變量保證與歷史演進(jìn)路徑。讀完本文你將掌握可編輯依賴機(jī)制的前因后果、底層行為約定以及它如何演化為現(xiàn)代 SwiftPM 的本地依賴與Package.resolved協(xié)作模型。一、背景與動機(jī)兩條幾乎矛盾的工作流SE-0082作者 Daniel Dunbar評審經(jīng)理 Anders Bertelrud狀態(tài)為Implemented (Swift 3.1)開篇即指出 SwiftPM 需要同時支撐兩種工作流而這兩者天然存在張力確定性構(gòu)建包管理器應(yīng)當(dāng)盡量保證構(gòu)建行為的確定性使包的其他使用者或部署場景與開發(fā)者看到完全一致的行為。因此默認(rèn)的依賴一致性模型應(yīng)當(dāng)很強(qiáng)——當(dāng)開發(fā)者期望針對某個 tag 構(gòu)建時包管理器要主動確保使用的是該 tag 對應(yīng)的精確源碼。如果開發(fā)者無意中針對被修改過的包進(jìn)行構(gòu)建而沒有顯式表達(dá)意圖默認(rèn)行為應(yīng)當(dāng)報錯或警告。上游迭代開發(fā)許多項(xiàng)目同時掌控多個相互依賴的包例如應(yīng)用 數(shù)個自研庫需要在不打 tag 的情況下跨包協(xié)同開發(fā)也鼓勵使用者把改動回饋給所依賴的包。這就要求包管理器允許開發(fā)者直接在依賴源碼上工作。從源碼結(jié)構(gòu)看這一矛盾在當(dāng)時的 SwiftPM 中體現(xiàn)得很直接舊實(shí)現(xiàn)總是把依賴源碼檢出到項(xiàng)目包旁邊的Packages子目錄目錄名由包名 tag拼接而成例如Packages/Foo-1.2.3。用戶雖然可以直接修改該目錄中的源碼并被構(gòu)建拾取但對包作者來說這個目錄通常不是他們希望編輯的規(guī)范位置更麻煩的是該位置的 git 倉庫處于tag 上而 tag 并不是適合做迭代開發(fā)的狀態(tài)。即使用戶手動切換分支也會出現(xiàn)目錄名內(nèi)嵌 tag 與目錄內(nèi)容不一致的混淆。此外包管理器天然還要處理update這類與依賴源碼交互的操作——直接支持用戶編輯源碼就要求包管理器回答如何處理用戶意圖與當(dāng)前樹內(nèi)容沖突的棘手問題。二、核心方案兩個支柱SE-0082 的解決思路由兩條緊密關(guān)聯(lián)的設(shè)計(jì)支柱構(gòu)成支柱一隱藏默認(rèn)檢出位置。把依賴源碼的默認(rèn)檢出位置改為隱藏作為實(shí)現(xiàn)細(xì)節(jié)存在默認(rèn)構(gòu)建總是精確使用依賴解析所選 tag 對應(yīng)的源碼。隱藏的理由很務(wù)實(shí)在一個成熟穩(wěn)定的生態(tài)里一次構(gòu)建會牽涉大量包其中大多數(shù)對當(dāng)前項(xiàng)目開發(fā)者毫無興趣——直接依賴的源碼或許值得一看但依賴的依賴的源碼對項(xiàng)目開發(fā)者而言就是實(shí)現(xiàn)細(xì)節(jié)。隱藏源碼的代價是查看源碼多了些步驟提案預(yù)期開發(fā)者能在--edit與結(jié)束編輯之間高效切換長期需求如查閱文檔則由網(wǎng)頁托管文檔等其他機(jī)制解決并且該默認(rèn)行為如果被證明有問題會重新評估。支柱二顯式的編輯模式。新增swift build --edit PACKAGE把一個既有依賴轉(zhuǎn)換為可編輯依賴editable dependency。一旦Packages中存在這樣的可編輯包swift build將始終直接使用該目錄中的精確源碼進(jìn)行構(gòu)建——無論其處于什么狀態(tài)、git 倉庫狀態(tài)如何、打了什么 tag、依賴解析期望哪個 tag。換言之它會直接就著現(xiàn)有源碼構(gòu)建。兩條支柱各司其職隱藏源碼讓針對已知成熟庫編程的常見場景減少干擾顯式切換到可編輯模式則讓針對規(guī)范版本集合構(gòu)建與針對可能被修改的包構(gòu)建兩種狀態(tài)之間的界限變得清晰可見。提案特別強(qiáng)調(diào)該功能被定義在swift build的行為層面而非 lockfile / 包固定pinning機(jī)制——因?yàn)橛每删庉嫲姹具€是規(guī)范解析版本最終是個體開發(fā)者的個人決定。團(tuán)隊(duì)協(xié)作場景如一組開發(fā)者共同編輯同一批包當(dāng)時尚無明確特性支撐但設(shè)計(jì)上預(yù)留了演進(jìn)空間。三、詳細(xì)設(shè)計(jì)七個具體步驟3.1 隱藏克隆位置與--get-package-path提案第一步是把包克隆移入既有的.build目錄同時新增顯式命令swift build --get-package-path PACKAGE以受支持的方式查詢包路徑。這樣設(shè)計(jì)的好處是未來若希望把緩存透明地遷移到共享位置用戶代碼不會因此失效。需要明確的是該命令在提案階段是受支持的方式意在替代用戶對包路徑的隱式假設(shè)。3.2Packages目錄的替換語義解析包圖時SwiftPM 會加載Packages目錄中存在的所有倉庫將其作為包圖中同名包的替換。關(guān)鍵細(xì)節(jié)初始階段不審計(jì)倉庫來源repository origin——這允許開發(fā)者開發(fā)尚未推送到任何服務(wù)器的包圖例如本地新建、還沒建遠(yuǎn)端倉庫的項(xiàng)目。當(dāng)可編輯包存在時它會被用來滿足依賴圖中該包的所有實(shí)例依賴圖中的包可以全部、部分或完全不進(jìn)入編輯狀態(tài)沒有任何限制。3.3 僅從根包加載提案明確規(guī)定不從根包以外的任何包加載可編輯包——即除根包外其他地方出現(xiàn)的Packages目錄將被忽略。這一約束保證了可編輯行為只由當(dāng)前項(xiàng)目的根包控制避免傳遞依賴中的同名目錄引發(fā)意外覆蓋。3.4--edit NAME與核心不變量新增--edit NAME子命令提案原文寫作swift build --edit最終落地為swift package edit。約束為被編輯的包必須是包圖中已存在的包。行為是取出依賴解析本應(yīng)選擇的那個精確 tag把該倉庫克隆到Packages/NAME并檢出到該 tag。該設(shè)計(jì)追求的核心不變量是從沒有任何可編輯依賴的初始狀態(tài)出發(fā)執(zhí)行下面三個連續(xù)命令每一步的構(gòu)建結(jié)果必須完全一致swift build swift build --edit NAME swift build即進(jìn)入編輯模式本身不應(yīng)該改變構(gòu)建產(chǎn)物——它只是把原本會從隱藏位置按 tag 檢出的源碼換成顯式放置在Packages/NAME的同一份 tag 源碼。開發(fā)者隨后對Packages/NAME的修改才會影響后續(xù)構(gòu)建。3.5--end-edit NAME結(jié)束編輯初版延遲實(shí)現(xiàn)提案計(jì)劃引入--end-edit NAME確切名稱當(dāng)時標(biāo)注為 TBD最終落地為swift package unedit讓包管理器恢復(fù)使用規(guī)范解析的包。實(shí)現(xiàn)上需要刪除Packages/NAME檢出這是需要格外謹(jǐn)慎的操作——但同時這也是向用戶傳達(dá)編輯中的倉庫尚未推回規(guī)范解析包的好時機(jī)例如改動未提交、未推送、未打 tag。提案明確表示該特性大概率從初始實(shí)現(xiàn)中推遲并建議用戶在特性到來前用rm -rf Packages/NAME手工結(jié)束編輯。這條臨時方案也解釋了為什么歷史上 Swift 文檔中一直保留著手工刪除Packages目錄的說明。3.6 可選的元數(shù)據(jù)文件提案考慮引入一個元數(shù)據(jù)文件記錄項(xiàng)目狀態(tài)與哪些包處于可編輯狀態(tài)。其價值有二提供更好的診斷信息記錄可編輯包的替代位置——當(dāng)作者在文件系統(tǒng)規(guī)范位置同時維護(hù)多個獨(dú)立項(xiàng)目、并希望其他包引用它做迭代開發(fā)時非常有用。在引入該文件之前這一行為可用Packages目錄內(nèi)的符號鏈接symbolic link模擬后續(xù) SE-0149 正是把這一設(shè)想正式化。設(shè)計(jì)上還有一個原則性決定若引入該文件文件系統(tǒng)中可編輯包的表現(xiàn)形式永遠(yuǎn)是權(quán)威數(shù)據(jù)源元數(shù)據(jù)文件只用于補(bǔ)充無法從文件系統(tǒng)推斷的診斷或信息絕不允許二者產(chǎn)生主從倒置。3.7--edit-all一鍵全量編輯提案還考慮提供swift build --edit-all標(biāo)志一次性把所有包切換到編輯模式。這一設(shè)想同樣服務(wù)于同時開發(fā)多個自己掌控的包的場景屬于可選增強(qiáng)。四、為什么不用 lockfile / pinning 語義實(shí)現(xiàn)提案在 Alternatives 一節(jié)專門討論了借助包固定/lockfile 機(jī)制承載迭代開發(fā)工作流的路線。結(jié)論是本提案的動機(jī)部分正源于在既有Packages目錄語義之上精確定義 package pinning 語義的困難。把編輯哪個包的決定放在swift build行為層面而非解析機(jī)制層面是因?yàn)樗情_發(fā)者個人工作流選擇不應(yīng)與團(tuán)隊(duì)共享的依賴解析狀態(tài)耦合。五、為未來擴(kuò)展預(yù)留的空間SE-0082 明確指出可編輯特性為后續(xù)工作流行為提供了新的掛載點(diǎn)并列舉了三個方向其中部分被后續(xù)提案逐一兌現(xiàn)推斷下一個語義版本允許用戶指定或自動推斷可編輯包的下一個語義版本然后仿佛該包已打上這個 tag地構(gòu)建整個包圖從而保證本地構(gòu)建結(jié)果與將來提交、打 tag 后的結(jié)果一致。安全退出編輯模式提供帶安全檢查的退出機(jī)制例如校驗(yàn)改動已提交、已推送、已打 tag。元數(shù)據(jù)變更告警當(dāng)可編輯包的項(xiàng)目元數(shù)據(jù)如依賴 tag 聲明發(fā)生變化時通知開發(fā)者——因?yàn)樘幱诰庉嫚顟B(tài)時這些改動不會被構(gòu)建反映出來靜默接受極易誤導(dǎo)。六、對現(xiàn)有包的影響與遷移考量這是對既有包檢出行為的實(shí)質(zhì)性變更老項(xiàng)目遺留的Packages目錄內(nèi)含大量帶 tag 名字的克隆會被新版本swift build視為一堆名字匹配不到依賴圖的編輯包。提案建議通過過渡機(jī)制檢測并警告這種情況甚至由此催生了在包管理器內(nèi)記錄項(xiàng)目最后一次使用的工具版本、以便自動啟用遷移行為的想法——這與后來 Swift tools-version 機(jī)制manifest 頭部// swift-tools-version:聲明的思路一脈相承后者正是 SwiftPM 管理行為遷移的標(biāo)準(zhǔn)手段。七、備選方案與設(shè)計(jì)取舍提案還記錄了兩個方向的取舍討論是否應(yīng)該默認(rèn)隱藏源碼支持方認(rèn)為成熟生態(tài)中依賴眾多且大多無趣隱藏可減少干擾反對方認(rèn)為增加了查看源碼的額外門檻。提案的折中是--edit與結(jié)束編輯之間高效切換 網(wǎng)頁文檔等替代機(jī)制并明確保留將來更改默認(rèn)行為的靈活性。是否用元數(shù)據(jù)驅(qū)動如上文 3.6 所述文件系統(tǒng)始終是權(quán)威元數(shù)據(jù)只做診斷增強(qiáng)。八、演進(jìn)與落地從 SE-0082 到現(xiàn)代 SwiftPMSE-0082 于 Swift 3.1 落地后可編輯包機(jī)制在后續(xù)提案中持續(xù)演進(jìn)從倉庫中的后續(xù)提案可以清晰看到這條脈絡(luò)SE-0149: 支持 Top of Tree 開發(fā)Swift 4.0把swift package edit擴(kuò)展出可選--path參數(shù)允許開發(fā)者把自己管理的既有檢出作為覆蓋override例如swift package edit bar --path ../bar。其行為與 SE-0082 3.6 節(jié)的設(shè)想完全對應(yīng)./Packages/bar變成指向給定路徑的符號鏈接映射記錄在工作區(qū)workspace中swift package unedit只刪除符號鏈接而不刪除用戶自己的檢出若給定位置沒有檢出包管理器會代勞首次克隆。SE-0175: 修訂依賴解析Swift 4.0明確了 edit 與解析命令的交互——swift package edit會隱式調(diào)用swift package resolve但即使 resolve 失敗、只要已識別并拉取到同名包仍允許進(jìn)入編輯可用于修復(fù)不可解析的依賴圖swift package unedit則是先解除編輯再執(zhí)行 resolve。同時處于編輯態(tài)的依賴允許與Package.resolved中記錄的版本不一致編輯中的包版本不會被自動改寫執(zhí)行swift package update時編輯中包及其依賴子樹下所有包的解析版本會從 resolved 文件中移除避免記錄下離開編輯模式后根本無法復(fù)現(xiàn)的版本組合。SE-0201: 本地依賴Swift 4.2提供Package.Dependency.package(path:)聲明式本地依賴直接用磁盤路徑替代 git URL包管理器不對本地包執(zhí)行任何 git 操作本地依賴會覆蓋包圖中同名依賴、不寫入Package.resolved與編輯模式行為一致且不允許對本地依賴再使用編輯特性。該提案的動機(jī)部分明確提到此前多個關(guān)聯(lián)包協(xié)同開發(fā)需要為每個依賴手工執(zhí)行swift package edit這正是 SE-0082 引入的工作流而本地依賴把這一摩擦進(jìn)一步降低。九、要點(diǎn)回顧設(shè)計(jì)決策SE-0082 內(nèi)容后續(xù)演進(jìn)默認(rèn)檢出位置從可見Packages/Name-tag移入.build實(shí)現(xiàn)細(xì)節(jié)保留至今可用--get-package-path查詢編輯入口swift build --edit PACKAGEswift package editSE-0149 增加--path結(jié)束編輯--end-edit延遲臨時用rm -rf Packages/NAMEswift package unedit與 resolve 聯(lián)動覆蓋語義按包名替換不審計(jì) origin僅根包生效SE-0201 本地依賴沿用同名覆蓋與解析狀態(tài)的關(guān)系編輯決定屬于個人工作流不進(jìn) lockfileSE-0175 規(guī)范了與Package.resolved的交互一言以蔽之SE-0082 奠定了 SwiftPM 處理依賴源碼歸屬權(quán)的基石——默認(rèn)把依賴源碼當(dāng)作不可改動的構(gòu)建輸入把修改依賴變成一種需要顯式聲明的、受控的工作流狀態(tài)并用進(jìn)入編輯不改變構(gòu)建結(jié)果這一不變量保證兩種模式之間無縫切換。理解這份提案也就理解了今天swift package edit、unedit、Package.resolved與本地依賴等現(xiàn)代工作流為何如此設(shè)計(jì)。贊分享文檔【免費(fèi)下載鏈接】swift-evolutionThis maintains proposals for changes and user-visible enhancements to the Swift Programming Language.項(xiàng)目地址https://gitcode.com/gh_mirrors/sw/swift-evolution點(diǎn)擊查看免費(fèi)下載相關(guān)推薦5步掌握Teable無代碼數(shù)據(jù)庫從Excel到智能業(yè)務(wù)系統(tǒng)5步掌握Teable無代碼數(shù)據(jù)庫從Excel到智能業(yè)務(wù)系統(tǒng) 你是否還在為數(shù)據(jù)管理發(fā)愁Excel表格越來越臃腫傳統(tǒng)數(shù)據(jù)庫又太復(fù)雜難懂?,F(xiàn)在Teable無代文檔Swift 增強(qiáng)浮點(diǎn)協(xié)議全解析SE-0067 中 FloatingPoint 與 BinaryFloatingPoint 的設(shè)計(jì)、實(shí)現(xiàn)與后續(xù)演進(jìn)Swift 增強(qiáng)浮點(diǎn)協(xié)議全解析SE 0067 中 FloatingPoint 與 BinaryFloatingPoint 的設(shè)計(jì)、實(shí)現(xiàn)與后續(xù)演進(jìn) 本文以 pr文檔深入解讀 Swift Evolution SE-0018靈活成員逐項(xiàng)初始化Flexible Memberwise Initialization的設(shè)計(jì)與后續(xù)演進(jìn)深入解讀 Swift Evolution SE 0018靈活成員逐項(xiàng)初始化Flexible Memberwise Initialization的設(shè)計(jì)與后續(xù)文檔創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考