mirror of
https://github.com/Lakr233/vphone-cli.git
synced 2026-09-02 02:34:29 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87f796c62a | ||
|
|
deabe6ffca | ||
|
|
2af884b56c | ||
|
|
977c17b56d | ||
|
|
53aa44dd57 | ||
|
|
58988bd518 | ||
|
|
72ccbde1de | ||
|
|
39b6d04108 | ||
|
|
339719f34d |
+1
-1
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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` |
|
||||
|
||||
## 常见问题
|
||||
|
||||
|
||||
+1
-1
Submodule scripts/resources updated: ee9a2845b3...2ef6b06a10
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,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)
|
||||
|
||||
Reference in New Issue
Block a user