9 Commits
Author SHA1 Message Date
zqxwce 87f796c62a resources: Update resources reference 2026-09-01 01:33:43 +03:00
zqxwceandClaude Fable 5 deabe6ffca catalog: Add iOS 27 beta 8 + cloudOS 26.4 firmware pairing
Add iPhone17,3 iOS 27.0 beta 8 (24A5430a) paired with cloudOS 26.4 to the
firmware catalog so it appears in the `fw prepare` picker, `fw catalog`,
and the `--json` report. Document it in the Tested Environments table
across README.md and the ja/ko/zh translations. Bump the hardcoded
pairing/menu count in FirmwarePickerTests 22 -> 23.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-09-01 01:33:43 +03:00
zqxwceandClaude Fable 5 2af884b56c resources: Bump storage submodule to fork main (drop ramdisk_input.tar.zst)
Fork main was force-pushed to ae7a0ac, orphaning the previously pinned
ee9a284. Advance the pin so fresh clones resolve against a live ref.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-29 03:44:16 +03:00
zqxwceandClaude Fable 5 977c17b56d resources: Point storage submodule to zqxwce fork
Retarget scripts/resources submodule URL from Lakr233 to the
zqxwce/vphone-cli-storage fork.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-29 03:24:32 +03:00
zqxwceandClaude Fable 5 53aa44dd57 catalog: Add iOS 27 beta 7 + cloudOS 26.4 firmware pairing
Add iPhone17,3 iOS 27.0 beta 7 (24A5424a) paired with cloudOS 26.4 to the
firmware catalog so it appears in the `fw prepare` picker, `fw catalog`,
and the `--json` report. Document it in the Tested Environments table
across README.md and the ja/ko/zh translations. Bump the hardcoded
pairing/menu count in FirmwarePickerTests 21 -> 22.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Ej64m761KR33KaNYh3BuTo
2026-08-25 11:07:35 +03:00
zqxwceandClaude Opus 4.8 58988bd518 catalog: Replace iOS 26.6.1 RC with release build 23G83
The bundled 26.6.1 IPSW pointed at the 23G82 release candidate, which
differs from the shipped release. Point it at the 23G83 final restore
and update the tested-environment tables accordingly.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-19 15:09:39 +03:00
Bent 72ccbde1de vphone-cli: Add VPHONE_ROOT env variable to override user data root 2026-08-18 11:48:47 +03:00
zqxwceandClaude Fable 5 39b6d04108 catalog: Add iOS 27 beta 6 + cloudOS 26.4 firmware pairing
Add iPhone17,3 iOS 27.0 beta 6 (24A5418b) paired with cloudOS 26.4 to the
firmware catalog so it appears in the `fw prepare` picker, `fw catalog`,
and the `--json` report. Document it in the Tested Environments table
across README.md and the ja/ko/zh translations. Bump the hardcoded
pairing/menu count in FirmwarePickerTests 20 -> 21.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-18 11:46:45 +03:00
zqxwceandClaude Fable 5 339719f34d catalog: Add iOS 26.6.1 + cloudOS 26.4 firmware pairing
Add iPhone17,3 iOS 26.6.1 (23G82) paired with cloudOS 26.4 to the
firmware catalog so it appears in the `fw prepare` picker, `fw catalog`,
and the `--json` report. Document it in the Tested Environments table
across README.md and the ja/ko/zh translations. Bump the hardcoded
pairing/menu count in FirmwarePickerTests 19 -> 20.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-13 17:58:15 +03:00
12 changed files with 88 additions and 14 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[submodule "scripts/resources"]
path = scripts/resources
url = https://github.com/Lakr233/vphone-cli-storage.git
url = https://github.com/zqxwce/vphone-cli-storage.git
[submodule "vendor/libcapstone-spm"]
path = vendor/libcapstone-spm
url = https://github.com/Lakr233/libcapstone-spm.git
+8 -1
View File
@@ -107,16 +107,19 @@ See [`research/0_binary_patch_comparison.md`](./research/0_binary_patch_comparis
## Locations
Everything vphone-cli creates lives under `~/.vphone/` — kept outside the repo and the `.app` so the signed bundle stays portable:
Everything vphone-cli creates lives under `~/.vphone/` — kept outside the repo and the `.app` so the signed bundle stays portable. Redirect the whole tree with `$VPHONE_ROOT`:
| Path | Contents |
| ----------------- | -------------------------------------------------------------------------------------------- |
| `~/.vphone/` | The per-user data root — override the entire location with `$VPHONE_ROOT`. |
| `~/.vphone/VMs/` | VM bundles — one directory per VM. This is the library; override with `$VPHONE_LIBRARY_ROOT`. |
| `~/.vphone/ipsws/`| Downloaded iPhone + cloudOS IPSWs, cached and reused across VMs. |
| `~/.vphone/tools/`| Cached APFS seal-volume artifacts (`apfs_sealvolume_<version>`) fetched during `fw prepare`. |
| `~/.vphone/debs/` | Cached `.deb` packages the `jb`/`exp` CFW install lays into the guest (Sileo, apt, …). |
| `~/.vphone/venv/` | Auto-provisioned Python environment (see [Python runtime](#python-runtime); override with `$VPHONE_VENV_DIR`). |
Precedence: the per-item overrides (`$VPHONE_LIBRARY_ROOT`, `$VPHONE_VENV_DIR`) win over `$VPHONE_ROOT`, which wins over the `~/.vphone` default. The `ipsws/`, `tools/`, and `debs/` caches always sit directly under whichever root is active.
## SIP/AMFI Relaxation
**Option A — fully disable SIP, then disable AMFI via boot-arg (most permissive).**
@@ -164,9 +167,13 @@ vphone-amfidont # .build/vphone-cli.app/Contents/Resources/vphone-amfido
| Mac16,11 26.2 | `17,3_26.5_23F77` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_26.5.2_23F84` | `26.4-23E5207q` |
| Mac16,6 26.4.1 | `17,3_26.6_23G71` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_26.6.1_23G83` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_27.0_24A5380h` | `26.4-23E5207q` |
| Mac16,6 26.4.1 | `17,3_27.0_24A5390f` | `26.4-23E5207q` |
| Mac16,6 26.6.1 | `17,3_27.0_24A5408d` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_27.0_24A5418b` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_27.0_24A5424a` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_27.0_24A5430a` | `26.4-23E5207q` |
## FAQ
+8 -1
View File
@@ -107,16 +107,19 @@ vphone-cli vm launch myphone # 6. 初回起動
## 場所
vphone-cli が生成するものはすべて `~/.vphone/` 以下に置かれます — 署名済みバンドルがポータブルであり続けるよう、リポジトリと `.app` の外に保管されます:
vphone-cli が生成するものはすべて `~/.vphone/` 以下に置かれます — 署名済みバンドルがポータブルであり続けるよう、リポジトリと `.app` の外に保管されます`$VPHONE_ROOT` でツリー全体をリダイレクトできます:
| パス | 内容 |
| ----------------- | ------------------------------------------------------------------------------------------ |
| `~/.vphone/` | ユーザー別データルート — `$VPHONE_ROOT` で場所全体を上書きします。 |
| `~/.vphone/VMs/` | VM バンドル — VM ごとに 1 ディレクトリ。これがライブラリです。`$VPHONE_LIBRARY_ROOT` で上書きできます。 |
| `~/.vphone/ipsws/`| ダウンロードされた iPhone + cloudOS の IPSW。キャッシュされ、複数の VM で再利用されます。 |
| `~/.vphone/tools/`| `fw prepare` 中に取得された APFS seal-volume アーティファクト(`apfs_sealvolume_<version>`)のキャッシュ。 |
| `~/.vphone/debs/` | `jb`/`exp` の CFW インストールがゲストに配置する `.deb` パッケージのキャッシュ(Sileo、apt など)。 |
| `~/.vphone/venv/` | 自動的にプロビジョニングされる Python 環境([Python ランタイム](#python-ランタイム) を参照。`$VPHONE_VENV_DIR` で上書き可能)。 |
優先順位: 項目ごとの上書き(`$VPHONE_LIBRARY_ROOT``$VPHONE_VENV_DIR`)が `$VPHONE_ROOT` より優先され、`$VPHONE_ROOT``~/.vphone` のデフォルトより優先されます。`ipsws/``tools/``debs/` キャッシュは、常に現在有効なルートの直下に置かれます。
## SIP/AMFI の緩和
**オプション A — SIP を完全に無効化し、boot-arg で AMFI を無効化する(最も緩い)。**
@@ -164,9 +167,13 @@ vphone-amfidont # ローカルビルドの場合は .build/vphone-cli.ap
| Mac16,11 26.2 | `17,3_26.5_23F77` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_26.5.2_23F84` | `26.4-23E5207q` |
| Mac16,6 26.4.1 | `17,3_26.6_23G71` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_26.6.1_23G83` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_27.0_24A5380h` | `26.4-23E5207q` |
| Mac16,6 26.4.1 | `17,3_27.0_24A5390f` | `26.4-23E5207q` |
| Mac16,6 26.6.1 | `17,3_27.0_24A5408d` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_27.0_24A5418b` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_27.0_24A5424a` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_27.0_24A5430a` | `26.4-23E5207q` |
## FAQ
+8 -1
View File
@@ -107,16 +107,19 @@ vphone-cli vm launch myphone # 6. 첫 부팅
## 위치
vphone-cli가 생성하는 모든 것은 `~/.vphone/` 아래에 있습니다 — 서명된 번들이 이식 가능하도록 저장소와 `.app` 외부에 보관됩니다:
vphone-cli가 생성하는 모든 것은 `~/.vphone/` 아래에 있습니다 — 서명된 번들이 이식 가능하도록 저장소와 `.app` 외부에 보관됩니다. `$VPHONE_ROOT`로 전체 트리를 리디렉션할 수 있습니다:
| 경로 | 내용 |
| ----------------- | ------------------------------------------------------------------------------------------ |
| `~/.vphone/` | 사용자별 데이터 루트 — `$VPHONE_ROOT`로 전체 위치를 재정의합니다. |
| `~/.vphone/VMs/` | VM 번들 — VM마다 하나의 디렉터리. 라이브러리이며, `$VPHONE_LIBRARY_ROOT`로 재정의할 수 있습니다. |
| `~/.vphone/ipsws/`| 다운로드된 iPhone + cloudOS IPSW, 캐시되어 여러 VM에서 재사용됩니다. |
| `~/.vphone/tools/`| `fw prepare` 중에 가져온 APFS seal-volume 아티팩트(`apfs_sealvolume_<version>`) 캐시. |
| `~/.vphone/debs/` | `jb`/`exp` CFW 설치가 게스트에 넣는 `.deb` 패키지 캐시 (Sileo, apt 등). |
| `~/.vphone/venv/` | 자동으로 프로비저닝되는 Python 환경 ([Python 런타임](#python-런타임) 참조; `$VPHONE_VENV_DIR`로 재정의). |
우선순위: 항목별 재정의(`$VPHONE_LIBRARY_ROOT`, `$VPHONE_VENV_DIR`)가 `$VPHONE_ROOT`보다 우선하고, `$VPHONE_ROOT``~/.vphone` 기본값보다 우선합니다. `ipsws/`, `tools/`, `debs/` 캐시는 항상 현재 활성 루트 바로 아래에 위치합니다.
## SIP/AMFI 완화
**방법 A — SIP를 완전히 비활성화한 후, boot-arg로 AMFI를 비활성화 (가장 관대).**
@@ -164,9 +167,13 @@ vphone-amfidont # 로컬 빌드의 경우 .build/vphone-cli.app/Contents
| Mac16,11 26.2 | `17,3_26.5_23F77` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_26.5.2_23F84` | `26.4-23E5207q` |
| Mac16,6 26.4.1 | `17,3_26.6_23G71` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_26.6.1_23G83` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_27.0_24A5380h` | `26.4-23E5207q` |
| Mac16,6 26.4.1 | `17,3_27.0_24A5390f` | `26.4-23E5207q` |
| Mac16,6 26.6.1 | `17,3_27.0_24A5408d` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_27.0_24A5418b` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_27.0_24A5424a` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_27.0_24A5430a` | `26.4-23E5207q` |
## FAQ
+8 -1
View File
@@ -107,16 +107,19 @@ vphone-cli vm launch myphone # 6. 首次启动
## 位置
vphone-cli 创建的所有内容都位于 `~/.vphone/` 下——保存在仓库和 `.app` 之外,以便签名后的包保持可移植:
vphone-cli 创建的所有内容都位于 `~/.vphone/` 下——保存在仓库和 `.app` 之外,以便签名后的包保持可移植。可用 `$VPHONE_ROOT` 重定向整个目录树
| 路径 | 内容 |
| ----------------- | -------------------------------------------------------------------------------- |
| `~/.vphone/` | 每用户数据根目录——用 `$VPHONE_ROOT` 覆盖整个位置。 |
| `~/.vphone/VMs/` | 虚拟机包——每个虚拟机一个目录。这是库;可用 `$VPHONE_LIBRARY_ROOT` 覆盖。 |
| `~/.vphone/ipsws/`| 已下载的 iPhone + cloudOS IPSW,缓存后在多个虚拟机间复用。 |
| `~/.vphone/tools/`| `fw prepare` 期间获取的 APFS seal-volume 制品(`apfs_sealvolume_<version>`)缓存。 |
| `~/.vphone/debs/` | `jb`/`exp` CFW 安装写入客户机的 `.deb` 包缓存(Sileo、apt 等)。 |
| `~/.vphone/venv/` | 自动配置的 Python 环境(见 [Python 运行时](#python-运行时);可用 `$VPHONE_VENV_DIR` 覆盖)。 |
优先级:单项覆盖(`$VPHONE_LIBRARY_ROOT``$VPHONE_VENV_DIR`)优先于 `$VPHONE_ROOT``$VPHONE_ROOT` 优先于 `~/.vphone` 默认值。`ipsws/``tools/``debs/` 缓存始终位于当前生效的根目录之下。
## 放宽 SIP/AMFI
**方案 A——完全禁用 SIP,然后通过 boot-arg 禁用 AMFI(最宽松)。**
@@ -164,9 +167,13 @@ vphone-amfidont # 本地构建见 .build/vphone-cli.app/Contents/Resourc
| Mac16,11 26.2 | `17,3_26.5_23F77` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_26.5.2_23F84` | `26.4-23E5207q` |
| Mac16,6 26.4.1 | `17,3_26.6_23G71` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_26.6.1_23G83` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_27.0_24A5380h` | `26.4-23E5207q` |
| Mac16,6 26.4.1 | `17,3_27.0_24A5390f` | `26.4-23E5207q` |
| Mac16,6 26.6.1 | `17,3_27.0_24A5408d` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_27.0_24A5418b` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_27.0_24A5424a` | `26.4-23E5207q` |
| Mac16,11 27.0b2 | `17,3_27.0_24A5430a` | `26.4-23E5207q` |
## 常见问题
@@ -55,11 +55,15 @@ public enum VPhoneFirmwareCatalog {
.init(iosName: "iOS 26.5", iosURL: "https://updates.cdn-apple.com/2026SpringFCS/fullrestores/122-63074/5E6B4A05-BDBC-45FE-9606-22B8F4315989/iPhone17,3_26.5_23F77_Restore.ipsw", cloudosName: "cloudOS 26.4", cloudosURL: cloud264),
.init(iosName: "iOS 26.5.2", iosURL: "https://updates.cdn-apple.com/2026SpringFCS/fullrestores/140-25549/1AFB1F72-E48E-476A-9C21-42B27C846C01/iPhone17,3_26.5.2_23F84_Restore.ipsw", cloudosName: "cloudOS 26.4", cloudosURL: cloud264),
.init(iosName: "iOS 26.6", iosURL: "https://updates.cdn-apple.com/2026SummerFCS/fullrestores/140-58193/1F477C3E-934B-43C0-B428-753B9E005EC0/iPhone17,3_26.6_23G71_Restore.ipsw", cloudosName: "cloudOS 26.4", cloudosURL: cloud264),
.init(iosName: "iOS 26.6.1", iosURL: "https://updates.cdn-apple.com/2026SummerFCS/fullrestores/140-93817/B5362BAA-F3EE-49C8-BA43-309F0DAD1362/iPhone17,3_26.6.1_23G83_Restore.ipsw", cloudosName: "cloudOS 26.4", cloudosURL: cloud264),
.init(iosName: "iOS 27 beta 1", iosURL: "https://updates.cdn-apple.com/2026SpringSeed/fullrestores/122-99394/32118457-A80B-4953-BF2A-11F74FD7D375/iPhone17,3_27.0_24A5355q_Restore.ipsw", cloudosName: "cloudOS 26.4", cloudosURL: cloud264),
.init(iosName: "iOS 27 beta 2", iosURL: "https://updates.cdn-apple.com/2026SpringSeed/fullrestores/140-21207/F0510574-F649-48C5-B535-0A477E342BFB/iPhone17,3_27.0_24A5370h_Restore.ipsw", cloudosName: "cloudOS 26.4", cloudosURL: cloud264),
.init(iosName: "iOS 27 beta 3", iosURL: "https://updates.cdn-apple.com/2026SpringSeed/fullrestores/140-35950/D135F5B5-C2BE-4630-8AE9-C78A6F0E8381/iPhone17,3_27.0_24A5380h_Restore.ipsw", cloudosName: "cloudOS 26.4", cloudosURL: cloud264),
.init(iosName: "iOS 27 beta 4", iosURL: "https://updates.cdn-apple.com/2026SpringSeed/fullrestores/140-57108/5E816D0E-89BB-4B95-8825-6A3EDF22E509/iPhone17,3_27.0_24A5390f_Restore.ipsw", cloudosName: "cloudOS 26.4", cloudosURL: cloud264),
.init(iosName: "iOS 27 beta 5", iosURL: "https://updates.cdn-apple.com/2026SpringSeed/fullrestores/140-86338/57B34BF9-3BF5-4B47-BCCA-81B282175957/iPhone17,3_27.0_24A5408d_Restore.ipsw", cloudosName: "cloudOS 26.4", cloudosURL: cloud264),
.init(iosName: "iOS 27 beta 6", iosURL: "https://updates.cdn-apple.com/2026SpringSeed/ad5b3026-b03e-4b21-8bcb-96d6ea527e09/iPhone17,3_27.0_24A5418b_Restore.ipsw", cloudosName: "cloudOS 26.4", cloudosURL: cloud264),
.init(iosName: "iOS 27 beta 7", iosURL: "https://updates.cdn-apple.com/2026SpringSeed/ad5a4f9d-f005-466b-bbcf-3b466040074b/iPhone17,3_27.0_24A5424a_Restore.ipsw", cloudosName: "cloudOS 26.4", cloudosURL: cloud264),
.init(iosName: "iOS 27 beta 8", iosURL: "https://updates.cdn-apple.com/2026SpringSeed/2d03d580-843b-4b2a-b09d-976b31c10744/iPhone17,3_27.0_24A5430a_Restore.ipsw", cloudosName: "cloudOS 26.4", cloudosURL: cloud264),
]
/// Distinct cloudOS images (first-seen order) for the "choose the cloudOS" prompt.
+2 -2
View File
@@ -41,8 +41,8 @@ public struct VPhoneLibrary: Sendable {
// `~/.vphone/VMs` deliberately space-free: bundle paths flow into the
// shell/make firmware pipeline, and "Application Support" (a space) breaks
// any unquoted expansion there. Keep the default path shell-safe.
return FileManager.default.homeDirectoryForCurrentUser
.appendingPathComponent(".vphone/VMs", isDirectory: true)
return VPhoneResources.userDataRoot()
.appendingPathComponent("VMs", isDirectory: true)
}
public func url(forName name: String) -> URL {
+10 -2
View File
@@ -70,9 +70,17 @@ public struct VPhoneResources: Sendable {
// MARK: - Cache dirs
public var userCacheDir: URL {
FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent(".vphone")
/// The per-user data root: `$VPHONE_ROOT` when set, else `~/.vphone`. Both
/// `VPhoneResources` (ipsws/tools/debs/venv) and `VPhoneLibrary` (VMs)
/// derive from this so one variable redirects everything vphone-cli creates.
public static func userDataRoot() -> URL {
if let root = ProcessInfo.processInfo.environment["VPHONE_ROOT"], !root.isEmpty {
return URL(fileURLWithPath: root, isDirectory: true)
}
return FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent(".vphone")
}
public var userCacheDir: URL { Self.userDataRoot() }
public var ipswCacheDir: URL { userCacheDir.appendingPathComponent("ipsws") }
public var sealVolumeCacheDir: URL { userCacheDir.appendingPathComponent("tools") }
public var debsCacheDir: URL { userCacheDir.appendingPathComponent("debs") }
@@ -10,8 +10,8 @@ struct FirmwarePickerTests {
// MARK: - Catalog integrity
@Test func catalogHasNineteenPairings() {
#expect(VPhoneFirmwareCatalog.pairings.count == 19)
@Test func catalogHasTwentyThreePairings() {
#expect(VPhoneFirmwareCatalog.pairings.count == 23)
}
@Test func everyPairingIsPopulated() {
@@ -106,7 +106,7 @@ struct FirmwarePickerTests {
iphone: nil, cloudos: nil, isInteractive: true,
read: reader(["1"]), write: { lines.append($0) })
let menu = lines.filter { $0.hasPrefix(" [") }
#expect(menu.count == 19)
#expect(menu.count == 23)
// Label text starts in one column regardless of 1- vs 2-digit index.
let labelStarts = Set(menu.map { $0.range(of: "] ")!.upperBound.utf16Offset(in: $0) })
#expect(labelStarts.count == 1)
+8
View File
@@ -50,10 +50,18 @@ struct LibraryTests {
#expect(VPhoneLibrary.defaultRoot().path == "/tmp/vphone-test-root")
}
@Test func defaultRootHonorsVPHONERoot() {
unsetenv("VPHONE_LIBRARY_ROOT")
setenv("VPHONE_ROOT", "/tmp/vphone-test-root", 1)
defer { unsetenv("VPHONE_ROOT") }
#expect(VPhoneLibrary.defaultRoot().path == "/tmp/vphone-test-root/VMs")
}
@Test func defaultRootIsShellSafe() {
// The default root feeds the shell/make firmware pipeline; a space in it
// (e.g. "Application Support") breaks unquoted expansion. Must stay space-free.
unsetenv("VPHONE_LIBRARY_ROOT")
unsetenv("VPHONE_ROOT")
#expect(!VPhoneLibrary.defaultRoot().path.contains(" "))
}
+27 -1
View File
@@ -27,6 +27,8 @@ struct ResourcesTests {
}
@Test func cacheDirsAreHomeRelativeAndToolsBinIsBaseRelative() {
// The VPHONE_ROOT override would relocate the cache; only assert the default.
if ProcessInfo.processInfo.environment["VPHONE_ROOT"] != nil { return }
let r = VPhoneResources(base: URL(fileURLWithPath: "/Applications/vphone-cli.app/Contents/Resources"))
#expect(r.userCacheDir.path.hasSuffix("/.vphone"))
#expect(r.toolsBinDir.path == r.base.appendingPathComponent(".tools/bin").path)
@@ -43,12 +45,36 @@ struct ResourcesTests {
}
@Test func managedVenvDefaultsUnderDotVphone() {
// The override env var would change this; only assert the default.
// The override env vars would change this; only assert the default.
if ProcessInfo.processInfo.environment["VPHONE_VENV_DIR"] != nil { return }
if ProcessInfo.processInfo.environment["VPHONE_ROOT"] != nil { return }
let r = VPhoneResources(base: URL(fileURLWithPath: "/x"))
#expect(r.managedVenvDir.path.hasSuffix("/.vphone/venv"))
}
@Test func userCacheDirHonorsVPHONERoot() {
unsetenv("VPHONE_VENV_DIR")
setenv("VPHONE_ROOT", "/tmp/vphone-test-root", 1)
defer { unsetenv("VPHONE_ROOT") }
let r = VPhoneResources(base: URL(fileURLWithPath: "/x"))
#expect(r.userCacheDir.path == "/tmp/vphone-test-root")
#expect(r.ipswCacheDir.path == "/tmp/vphone-test-root/ipsws")
#expect(r.sealVolumeCacheDir.path == "/tmp/vphone-test-root/tools")
#expect(r.debsCacheDir.path == "/tmp/vphone-test-root/debs")
#expect(r.managedVenvDir.path == "/tmp/vphone-test-root/venv")
}
@Test func managedVenvOverrideBeatsVPHONERoot() {
setenv("VPHONE_ROOT", "/tmp/vphone-test-root", 1)
setenv("VPHONE_VENV_DIR", "/tmp/custom-venv", 1)
defer {
unsetenv("VPHONE_ROOT")
unsetenv("VPHONE_VENV_DIR")
}
let r = VPhoneResources(base: URL(fileURLWithPath: "/x"))
#expect(r.managedVenvDir.path == "/tmp/custom-venv")
}
@Test func pythonUsabilityProbeRejectsMissingAcceptsDevVenv() {
let cwd = URL(fileURLWithPath: FileManager.default.currentDirectoryPath)
let r = VPhoneResources(base: cwd)