跳到正文
本頁目錄

狀態檔

本頁說明 .lip/state.json,讀完後你能看懂 lip 為一個工作區記錄了什麼,以及每個成員的用途。

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 會復原其對工作區的修改,狀態檔保持原樣,因此兩者始終一致(參見 lip 的工作方式)。

lip 只會整體寫入狀態檔:先寫 .lip/state.json.tmp,再把它重命名為 .lip/state.json。因此,在 lip 工作期間讀取狀態檔的程式,看到的要麼是操作之前的檔案,要麼是操作之後的檔案,不會是寫了一半的。lip list 就是這樣讀取的,不取得工作區鎖。

結構

狀態檔是一個 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;遊戲 github.com/LiteLDev/bds 不來自任何儲存庫,也沒有。
  • 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 及更早版本的工作區見 lip v0.x 的工作區。

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 的套件會被丟棄。

另請參閱