跳到正文
本頁目錄

狀態文件

lip 在工作區的狀態文件中記錄工作區狀態:安裝了哪些包、它們的確切版本、來源,以及它們寫入磁盤的文件。

位置

狀態文件是工作區根目錄下的 .lip/state.json。在 Windows 上,lip 創建 .lip 目錄時會為其設置隱藏屬性;在其他平臺上,它的名稱本身就使其隱藏。

由於狀態文件位於工作區目錄之中,而不是與其路徑綁定,移動、重命名或複製工作區後,狀態文件會隨之保留,已安裝的包也隨之保留。

.lip 為 lip 保留:安裝的包若要把文件寫入工作區根目錄下的 .lip 或其下任何位置,安裝會失敗;purge 模式也永遠不會匹配 .lip 及其下的任何內容。

作用

狀態文件有以下幾個用途:

  1. 狀態追蹤:作為工作區安裝狀態的唯一真實來源。
  2. 可復現性:記錄安裝每個已安裝包時所用的包文件,對於來自 git 倉庫的包還記錄其所在的提交。當 lip 再次需要某個包時,會用該包文件安裝它,而不是重新解析該包。
  3. 卸載:lip 追蹤包寫入磁盤的每個文件,使 lip uninstall 能幹淨地刪除與包相關的所有文件,避免工作區中殘留"腐爛文件"。
  4. 依賴圖:區分用戶顯式安裝的包和作為依賴安裝的包。這樣 lip uninstall 也能移除不再被任何顯式安裝的包需要的依賴,lip list 也能把兩組分開顯示。
  5. 環境:一旦得知工作區的運行端和平臺,就將其記錄下來,使後續命令使用同一環境。

狀態文件在一次操作的所有包都安裝或卸載完成後才替換一次。若操作失敗,lip 會撤銷其對工作區的修改,狀態文件保持原樣,因此兩者始終一致(參見內部機制)。

結構

狀態文件是一個 JSON 文件,由 JSON Schema state.schema.json 描述:

json
{
  "format": 4,
  "side": "server",
  "platform": "win-x64",
  "packages": [...]
}

字段

  • format:狀態文件的格式,4。
  • side:工作區的運行端,"server" 或 "client"。lip 寫入 "server"。
  • platform:工作區的平臺,一個 .NET RID。
  • packages:已安裝的包,按安裝順序排列:一個包排在滿足其依賴的包之後。

side 和 platform 總是存在且從不為 null;缺少它們的狀態文件無效。沒有狀態文件的工作區從其第一次 setup、install、uninstall 或 update 獲得環境(參見 lip install)。

包條目

每個包恰好由以下成員記錄:

  • manifest:安裝該包時所用的完整包文件。對於早期格式的 tooth.json,它是 lip 針對工作區環境從中派生的包文件。其 id 是包 ID,version 是已安裝的版本。
  • variant:安裝來源的變體,默認變體為 ""。它與 manifest 的 id 一起構成包的身份。
  • explicit:
    • true:該包由用戶顯式安裝(例如 lip install <package>)。
    • false:該包作為另一個包的依賴安裝。
  • ref:包的安裝來源:傳給 lip install 或 lip update 的參數(例如 github.com/user/repo、github.com/user/repo#lua@branch:main 或 https:// URL;本地路徑記錄為其絕對路徑的 file: URI),lip setup 安裝遊戲或加載器所用的來源(例如 github.com/LiteLDev/bds@1.21.0),對於依賴則是該依賴的鍵。lip update 會再次請求它。
  • commit:僅用於來自 git 倉庫的包:其歸檔所在的提交,以小寫十六進制表示。來自 URL 或本地路徑的包沒有 commit。
  • files:包擁有的文件,相對於工作區根目錄,以 / 分隔。

已安裝的條目是 manifest.variants[variant] 中 side 和 platform 與工作區相同的那個條目。

lip 只按身份、版本和提交比較已安裝的包與它解析出的包:身份和版本相同、且都不來自 git 倉庫或來自同一提交的兩個包是同一個包,即使 URL 或本地路徑的文件此後已經改變。下載的 ZIP 歸檔或資源的校驗和既不記錄也不檢查。

當 lip 再次需要某個已安裝包的文件時,它用記錄的 manifest 安裝該包:對於來自 git 倉庫的包,從記錄的提交安裝(即使它來自一個此後已前進的分支);否則從其 ref 現在指向的歸檔安裝。卸載不需要兩者中的任何一個。

示例

json
{
  "format": 4,
  "side": "server",
  "platform": "win-x64",
  "packages": [
    {
      "manifest": {
        "format": 4,
        "id": "github.com/example/MyMod",
        "version": "1.0.0",
        "variants": {
          "": [
            {
              "side": "server",
              "platform": "win-x64",
              "deps": { "github.com/LiteLDev/LeviLamina": ">=1.0.0 <2.0.0" },
              "assets": [
                {
                  "type": "mcmod",
                  "urls": ["https://github.com/example/MyMod/releases/download/v1.0.0/MyMod-server-win-x64.zip"]
                }
              ]
            }
          ]
        }
      },
      "variant": "",
      "explicit": true,
      "ref": "github.com/example/MyMod",
      "commit": "0123456789abcdef0123456789abcdef01234567",
      "files": ["mods/MyMod/MyMod.dll", "mods/MyMod/manifest.json"]
    }
  ]
}

lip v0.39.x 的工作區

lip v0.39.x 的狀態文件同樣是格式 4,但在其根部以及每個記錄的 manifest 的條目中,把運行端寫作 platform、把平臺寫作 runtime。lip 不讀取這樣的狀態文件:含有 runtime、或 platform 為 "server" 或 "client" 的根部或條目會使命令失敗,並給出消息,提示把 platform 改名為 side、把 runtime 改名為 platform。lip 不會遷移它;請在根部以及每個 manifest 的每個條目中改名這兩個鍵。下一節介紹 lip v0.37.0 及更早版本的工作區。

linux-x64 的工作區

早期版本的 lip 曾通過 --platform 為 win-x64 以外的平臺安裝包。lip 把記錄平臺 linux-x64 的狀態文件當作 win-x64 的狀態文件讀取,其中的 github.com/LiteLDev/bds 是其變體 github.com/LiteLDev/bds#linux,即 Linux 版服務器,下一次 setup、install、uninstall 或 update 會如此記錄它。記錄了其他任何包的 linux-x64 狀態文件會使讀取它的每條命令失敗,並給出指明該包的消息:請在新工作區中重新安裝這些包。記錄其他平臺的狀態文件會使 setup、install、uninstall、update 和 run 失敗。

lip v0.x 的工作區

lip v0.37.0 及更早版本的工作區在其根目錄中有一個格式版本 3 的 tooth_lock.json,而沒有狀態文件。lip 會自動遷移它:

  • lip list 把它讀作它所代表的狀態文件,不做修改。
  • 下一次 lip setup、lip install、lip uninstall 或 lip update 把該狀態文件寫為 .lip/state.json,並刪除 tooth_lock.json。

每個包保留其變體、是否顯式安裝,以及它擁有的、位於工作區之下的文件;其 ref 為其包 ID(加上 #<variant>),其 commit 從其倉庫的版本標籤 v<version> 查得。無法查得該提交時,命令會失敗。lip 無法針對工作區環境讀取其 tooth.json 的包會被丟棄。