peachsim 0.1.1625 → 0.1.1635
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +10 -1
- package/cli/app-config.ts +4 -1
- package/cli/app-fonts.ts +37 -17
- package/cli/app-stubs.ts +224 -9
- package/cli/bridge-flow-runner.ts +64 -43
- package/cli/command-registry.ts +1 -0
- package/cli/commands/control.ts +283 -49
- package/cli/commands/doctor.ts +17 -184
- package/cli/commands/flow.ts +79 -11
- package/cli/commands/inspect/core.ts +10 -5
- package/cli/commands/inspect/settling.ts +14 -2
- package/cli/commands/inspect/wait-ready.ts +12 -0
- package/cli/commands/inspect.ts +26 -3
- package/cli/commands/install-desktop.ts +1 -0
- package/cli/commands/maestro-compare.ts +97 -38
- package/cli/commands/maestro.ts +9 -1
- package/cli/commands/record.ts +21 -1
- package/cli/commands/screenshot.ts +23 -1
- package/cli/commands/serve.ts +7 -2
- package/cli/commands/setup.ts +19 -42
- package/cli/commands/swift.ts +5 -0
- package/cli/commands/upload.ts +46 -7
- package/cli/desktop-companion.ts +102 -17
- package/cli/drivers/desktop.ts +14 -1
- package/cli/drivers/playwright-sim-host.ts +38 -3
- package/cli/drivers/playwright.ts +9 -8
- package/cli/drivers/types.ts +5 -0
- package/cli/maestro-accessibility.ts +1 -1
- package/cli/maestro-compare.ts +84 -12
- package/cli/main.ts +2 -1
- package/cli/outbound-endpoints.ts +13 -1
- package/cli/pause-aware-timeout.ts +102 -0
- package/cli/scene-video.ts +89 -0
- package/cli/ws-bridge.ts +23 -14
- package/detox/attempt-events.cjs +4 -0
- package/detox/index.ts +167 -142
- package/detox/motion-change.cjs +57 -21
- package/detox/motion-change.d.cts +7 -2
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +13 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +14 -8
- package/dist-lib/bridge-contract.mjs +13 -7
- package/dist-lib/bundle-channel.cjs +9536 -7604
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +6 -3
- package/dist-lib/config.mjs +6 -3
- package/dist-lib/detox/index.cjs +895 -664
- package/dist-lib/dev-bundle-resolution.cjs +14 -2
- package/dist-lib/expo-swift-bundle.cjs +7818 -5916
- package/dist-lib/expo-swift-metadata.cjs +3 -1
- package/dist-lib/expo-swift-metadata.mjs +3 -1
- package/dist-lib/home-paths.cjs +32 -3
- package/dist-lib/host/bridge-host.cjs +8340 -6392
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +812 -339
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/kotlin-host.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +391 -28
- package/dist-lib/native-app-identity-project.cjs +55 -2
- package/dist-lib/native-app-identity-project.mjs +55 -2
- package/dist-lib/native-app-identity.cjs +53 -1
- package/dist-lib/native-app-identity.mjs +52 -1
- package/dist-lib/native-firebase-metadata.cjs +1 -1
- package/dist-lib/native-firebase-metadata.mjs +1 -1
- package/dist-lib/plist.cjs +1 -1
- package/dist-lib/plist.mjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +5 -1
- package/dist-lib/react-native-host-modules.mjs +5 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +15 -3
- package/dist-lib/sdk.cjs +27 -11
- package/dist-lib/sdk.mjs +27 -10
- package/dist-lib/skills.cjs +12276 -8947
- package/dist-lib/swift-compile.cjs +924 -118
- package/dist-lib/swift-compile.mjs +966 -152
- package/dist-lib/swift-package.cjs +12 -3
- package/dist-lib/swift-package.mjs +12 -3
- package/dist-lib/swift-submit.cjs +7 -1
- package/dist-lib/swift-submit.mjs +5 -1
- package/dist-lib/swift-toolchain.cjs +133 -18
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +1955 -498
- package/dist-lib/vite.cjs +3 -1
- package/dist-lib/worklet-executable.cjs +1 -1
- package/dist-lib/worklet-executable.mjs +1 -1
- package/kotlin/AppSources/dev/peach/app/PeachDrawable.kt +21 -14
- package/kotlin/Sources/androidx/annotation/DrawableRes.kt +14 -0
- package/package.json +1 -1
- package/scripts/dev-server-scanner.ts +2 -1
- package/skills/peach-perf/SKILL.md +11 -5
- package/skills/peach-setup/SKILL.md +16 -19
- package/src/bridge-constants.ts +11 -0
- package/src/bridge-contract.ts +22 -34
- package/src/config.ts +15 -0
- package/src/desktop-host-delivery.ts +5 -1
- package/src/dev-bundle-resolution.ts +2 -1
- package/src/expo-manifest-body.ts +13 -0
- package/src/expo-swift-host.ts +191 -47
- package/src/expo-swift-ready.ts +78 -0
- package/src/expoSwiftContract.ts +13 -0
- package/src/home-paths.ts +48 -2
- package/src/host/bridge-host.ts +5 -2
- package/src/native-app-identity-project.ts +26 -2
- package/src/native-app-identity.ts +90 -0
- package/src/native-firebase-config.ts +209 -13
- package/src/process-group.ts +25 -2
- package/src/react-native-bridge-modules.ts +416 -0
- package/src/react-native-host-modules.ts +4 -0
- package/src/swift-binary-modules.ts +2 -2
- package/src/swift-compile.ts +835 -84
- package/src/swift-compiler-digest.ts +14 -0
- package/src/swift-distribution.lock.json +14 -12
- package/src/swift-host.ts +91 -29
- package/src/swift-icu.ts +14 -6
- package/src/swift-objc-sdk.ts +133 -10
- package/src/swift-objc-standin.ts +25 -3
- package/src/swift-package-manifest.ts +21 -6
- package/src/swift-package.ts +15 -1
- package/src/swift-packages.ts +119 -60
- package/src/swift-standin-emit.ts +57 -9
- package/src/swift-standins.ts +168 -20
- package/src/swift-submit.ts +10 -0
- package/src/swift-toolchain.ts +149 -23
- package/src/vite-plugin.ts +12 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto'
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
|
|
5
|
+
// the lowering and manifest code in swift-compile.ts and its design-time lowering
|
|
6
|
+
// decide the emitted output, so their text addresses every swift artifact. bundled
|
|
7
|
+
// builds cannot read these files at runtime, so build-cli injects this digest.
|
|
8
|
+
export function swiftCompilerSourceDigest(srcDir: string): string {
|
|
9
|
+
const hash = createHash('sha256')
|
|
10
|
+
for (const file of ['swift-compile.ts', 'swift-design-time.ts']) {
|
|
11
|
+
hash.update(readFileSync(path.join(srcDir, file)))
|
|
12
|
+
}
|
|
13
|
+
return hash.digest('hex')
|
|
14
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"id": "
|
|
3
|
-
"release": "swift-6.4.0-RELEASE",
|
|
4
|
-
"wasmSdkId": "swift-6.4.0-RELEASE_wasm-peach-
|
|
5
|
-
"wasmSdkUrl": "https://r2.sootsim.com/swift-wasm-sdk/swift-6.4.0-RELEASE_wasm-peach-
|
|
6
|
-
"wasmSdkChecksum": "
|
|
7
|
-
"source": "
|
|
2
|
+
"id": "4fdcd218fa180b52",
|
|
3
|
+
"release": "swift-6.4.0-RELEASE-custom-91504a66b3f012ac",
|
|
4
|
+
"wasmSdkId": "swift-6.4.0-RELEASE_wasm-peach-7fd9a101",
|
|
5
|
+
"wasmSdkUrl": "https://r2.sootsim.com/swift-wasm-sdk/swift-6.4.0-RELEASE_wasm-peach-7fd9a101.artifactbundle.tar.gz",
|
|
6
|
+
"wasmSdkChecksum": "72f7fec1d090d142d26148d6cc0cd5b1ce78da70bb97bd577dc1482eaf0299b2",
|
|
7
|
+
"source": "80c26dea3c4bbf0e29458c33a3a0e856b0942564",
|
|
8
8
|
"targets": [
|
|
9
9
|
"System",
|
|
10
10
|
"_LocationEssentials",
|
|
@@ -36,12 +36,14 @@
|
|
|
36
36
|
"FoundationNetworking",
|
|
37
37
|
"DeveloperToolsSupport",
|
|
38
38
|
"SwiftUI",
|
|
39
|
+
"os_workgroup",
|
|
39
40
|
"Dispatch",
|
|
40
41
|
"DarwinRecords",
|
|
41
42
|
"Darwin",
|
|
42
43
|
"MachO",
|
|
43
44
|
"ObjectiveC",
|
|
44
45
|
"PeachObjC",
|
|
46
|
+
"UIUtilities",
|
|
45
47
|
"UIKitCore",
|
|
46
48
|
"PeachICU",
|
|
47
49
|
"PeachCMark",
|
|
@@ -179,16 +181,16 @@
|
|
|
179
181
|
},
|
|
180
182
|
"hosts": {
|
|
181
183
|
"darwin-arm64": {
|
|
182
|
-
"sha256": "
|
|
183
|
-
"size":
|
|
184
|
+
"sha256": "2b6768539f39bbdc2d77447fc91b00e9a7ee2d9ed732ea10e67a7b05c1c854ea",
|
|
185
|
+
"size": 69899802
|
|
184
186
|
},
|
|
185
187
|
"linux-x64": {
|
|
186
|
-
"sha256": "
|
|
187
|
-
"size":
|
|
188
|
+
"sha256": "2d357dc6c24559b1e4f792c4142de2608e2dd91a2b322c74013af31a9346ad6e",
|
|
189
|
+
"size": 69902826
|
|
188
190
|
},
|
|
189
191
|
"linux-arm64": {
|
|
190
|
-
"sha256": "
|
|
191
|
-
"size":
|
|
192
|
+
"sha256": "fdbdc2b25d102db38da6c00e74c6d198b87537aefe74365ef65793ec6feb3faa",
|
|
193
|
+
"size": 69900830
|
|
192
194
|
}
|
|
193
195
|
}
|
|
194
196
|
}
|
package/src/swift-host.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { createHash } from 'node:crypto'
|
|
|
2
2
|
// the node host for every Swift preview: package inputs, one compile and
|
|
3
3
|
// immutable artifact addresses. vite and the foreground CLI adapt this host.
|
|
4
4
|
import fs from 'node:fs'
|
|
5
|
-
import os from 'node:os'
|
|
6
5
|
import path from 'node:path'
|
|
7
6
|
import {
|
|
8
7
|
enumerateBundleColors,
|
|
@@ -11,8 +10,10 @@ import {
|
|
|
11
10
|
enumerateBundleResources,
|
|
12
11
|
resolveSwiftImageResourceUrls,
|
|
13
12
|
} from '../../sootsim-swift/src/bundleAssets'
|
|
13
|
+
import { compileStringCatalog } from '../../sootsim-swift/src/stringCatalog'
|
|
14
14
|
import { authHeaderValue, resolveCliAuth } from '../cli/auth'
|
|
15
15
|
import { resolveContrastBackendOrigin } from './backend-origin'
|
|
16
|
+
import { cacheDir } from './home-paths'
|
|
16
17
|
import iosSdk from './ios-sdk-frameworks.json' with { type: 'json' }
|
|
17
18
|
import { swiftBinaryModules } from './swift-binary-modules'
|
|
18
19
|
import {
|
|
@@ -39,13 +40,13 @@ import {
|
|
|
39
40
|
} from './swift-package'
|
|
40
41
|
import { swiftPackageManifest } from './swift-package-manifest'
|
|
41
42
|
import {
|
|
42
|
-
|
|
43
|
+
remoteSwiftCheckouts,
|
|
43
44
|
resolveSwiftPackages,
|
|
44
45
|
type SwiftPackageBinary,
|
|
45
46
|
type SwiftPackageGap,
|
|
46
47
|
type SwiftPackages,
|
|
47
48
|
} from './swift-packages'
|
|
48
|
-
import { readPackageFile } from './swift-source-file'
|
|
49
|
+
import { readPackageFile as readSwiftSourceFile } from './swift-source-file'
|
|
49
50
|
import { readSwiftStandinBehavior } from './swift-standin-config'
|
|
50
51
|
import {
|
|
51
52
|
standinGenerationInputs,
|
|
@@ -68,6 +69,7 @@ import {
|
|
|
68
69
|
MAX_SWIFT_COMPILE_IMAGE_TOTAL_BYTES,
|
|
69
70
|
isSwiftNativeModules,
|
|
70
71
|
compileSwiftProject,
|
|
72
|
+
DEFAULT_SWIFT_COMPILE_BUILD_MS,
|
|
71
73
|
httpSwiftCompileSubmit,
|
|
72
74
|
swiftNativeEntry,
|
|
73
75
|
type SwiftImageUpload,
|
|
@@ -242,6 +244,8 @@ interface XcodeProjectEntry {
|
|
|
242
244
|
packages?: {
|
|
243
245
|
key: string
|
|
244
246
|
standinKey: string
|
|
247
|
+
/** generation always uses the original closure, before stand-ins replace targets. */
|
|
248
|
+
binaries: SwiftPackageBinary[]
|
|
245
249
|
packages: SwiftPackages
|
|
246
250
|
standins: SwiftStandin[]
|
|
247
251
|
/** why a framework the project vendors got no stand-in, by name. */
|
|
@@ -324,16 +328,18 @@ function swiftPackages(
|
|
|
324
328
|
// emitter), so a changed input rebuilds instead of reusing stale output.
|
|
325
329
|
let cached = entry.packages
|
|
326
330
|
if (cached?.key !== key) {
|
|
331
|
+
const packages = resolveSwiftPackages({
|
|
332
|
+
rootDir: app.rootDir,
|
|
333
|
+
resolved: app.packageResolved,
|
|
334
|
+
products: app.linkedProducts,
|
|
335
|
+
localDirs: app.localPackageDirs,
|
|
336
|
+
provided: entry.provided,
|
|
337
|
+
})
|
|
327
338
|
cached = {
|
|
328
339
|
key,
|
|
329
340
|
standinKey: '',
|
|
330
|
-
packages
|
|
331
|
-
|
|
332
|
-
resolved: app.packageResolved,
|
|
333
|
-
products: app.linkedProducts,
|
|
334
|
-
localDirs: app.localPackageDirs,
|
|
335
|
-
provided: entry.provided,
|
|
336
|
-
}),
|
|
341
|
+
packages,
|
|
342
|
+
binaries: packages.binaries,
|
|
337
343
|
standins: [],
|
|
338
344
|
projectGaps: new Map(),
|
|
339
345
|
}
|
|
@@ -360,10 +366,7 @@ function swiftPackages(
|
|
|
360
366
|
]
|
|
361
367
|
: [],
|
|
362
368
|
)
|
|
363
|
-
const reached = [
|
|
364
|
-
...cached.packages.binaries.filter((binary) => binary.reached),
|
|
365
|
-
...vendored,
|
|
366
|
-
]
|
|
369
|
+
const reached = [...cached.binaries.filter((binary) => binary.reached), ...vendored]
|
|
367
370
|
if (entry.moduleRoot && entry.provided && reached.length > 0) {
|
|
368
371
|
const resolved = swiftModuleToolchain(entry.moduleRoot)
|
|
369
372
|
const toolchain = {
|
|
@@ -385,6 +388,8 @@ function swiftPackages(
|
|
|
385
388
|
]),
|
|
386
389
|
binaryGaps: built.gaps,
|
|
387
390
|
})
|
|
391
|
+
for (const target of new Set(built.standins.map((standin) => standin.target)))
|
|
392
|
+
console.error(`Peach: target ${target} was replaced with a stand-in`)
|
|
388
393
|
cached.standins = built.standins
|
|
389
394
|
cached.projectGaps = new Map(
|
|
390
395
|
vendored.flatMap(({ target }) => {
|
|
@@ -408,14 +413,17 @@ const XCODE_FRAMEWORKS_DIR = '__frameworks__'
|
|
|
408
413
|
// remote package checkouts compile here: swiftpm owns `.build` in the
|
|
409
414
|
// compile's package root as its scratch directory.
|
|
410
415
|
const XCODE_PACKAGES_DIR = '__packages__'
|
|
411
|
-
const CHECKOUTS_PREFIX = `${REMOTE_CHECKOUTS.split(path.sep).join(path.posix.sep)}/`
|
|
412
416
|
|
|
413
417
|
// the compile input key of a root-relative path in an xcode layout.
|
|
414
418
|
function xcodeInputKey(layout: XcodeLayout, file: string, relative: string): string {
|
|
415
419
|
const owner = layout.targetDirs.get(file)
|
|
416
420
|
if (owner) return path.posix.join(owner, relative)
|
|
417
|
-
|
|
418
|
-
|
|
421
|
+
const checkouts = remoteSwiftCheckouts(layout.app.rootDir)
|
|
422
|
+
return file.startsWith(`${checkouts}${path.sep}`)
|
|
423
|
+
? path.posix.join(
|
|
424
|
+
XCODE_PACKAGES_DIR,
|
|
425
|
+
path.relative(checkouts, file).split(path.sep).join('/'),
|
|
426
|
+
)
|
|
419
427
|
: relative
|
|
420
428
|
}
|
|
421
429
|
|
|
@@ -489,6 +497,7 @@ function xcodeLayout(root: string): XcodeLayout | null {
|
|
|
489
497
|
targets.push({
|
|
490
498
|
name: standin.module,
|
|
491
499
|
path: path.posix.join(SWIFT_STANDINS_DIR, standin.module),
|
|
500
|
+
dependencies: standin.dependencies?.map((name) => ({ kind: 'target', name })),
|
|
492
501
|
executable: false,
|
|
493
502
|
resources: false,
|
|
494
503
|
exclude: [],
|
|
@@ -500,7 +509,7 @@ function xcodeLayout(root: string): XcodeLayout | null {
|
|
|
500
509
|
const packageConfiguration = app.configuration === 'Debug' ? 'debug' : 'release'
|
|
501
510
|
for (const target of packages.targets) {
|
|
502
511
|
const relative = path.relative(
|
|
503
|
-
target.remote ?
|
|
512
|
+
target.remote ? remoteSwiftCheckouts(root) : root,
|
|
504
513
|
target.dir,
|
|
505
514
|
)
|
|
506
515
|
if (
|
|
@@ -524,6 +533,13 @@ function xcodeLayout(root: string): XcodeLayout | null {
|
|
|
524
533
|
)
|
|
525
534
|
.map((define) => define.name),
|
|
526
535
|
],
|
|
536
|
+
linkedLibraries: target.packageLibraries
|
|
537
|
+
.filter(
|
|
538
|
+
(library) =>
|
|
539
|
+
library.configuration === null ||
|
|
540
|
+
library.configuration === packageConfiguration,
|
|
541
|
+
)
|
|
542
|
+
.map((library) => library.name),
|
|
527
543
|
})
|
|
528
544
|
if (target.resources) {
|
|
529
545
|
resourceBundles.push({
|
|
@@ -568,14 +584,19 @@ function xcodeManifest(layout: XcodeLayout): string {
|
|
|
568
584
|
...(target.mainActorIsolation ? ['.defaultIsolation(MainActor.self)'] : []),
|
|
569
585
|
...(target.defines ?? []).map((name) => `.define(${JSON.stringify(name)})`),
|
|
570
586
|
].join(', ')}]`
|
|
587
|
+
const libraries = (target: SwiftPackageTarget) =>
|
|
588
|
+
target.linkedLibraries?.length
|
|
589
|
+
? `, linkerSettings: [${target.linkedLibraries.map((name) => `.linkedLibrary(${JSON.stringify(name)})`).join(', ')}]`
|
|
590
|
+
: ''
|
|
571
591
|
return [
|
|
572
592
|
'// swift-tools-version: 6.2',
|
|
573
593
|
'import PackageDescription',
|
|
574
594
|
'let package = Package(name: "app", targets: [',
|
|
575
595
|
` .executableTarget(name: "${layout.app.moduleName}", path: "${XCODE_APP_DIR}", ${settings(layout.app)}),`,
|
|
576
|
-
...layout.targets.map(
|
|
577
|
-
|
|
578
|
-
` .
|
|
596
|
+
...layout.targets.map((target) =>
|
|
597
|
+
target.systemLibrary
|
|
598
|
+
? ` .systemLibrary(name: "${target.name}", path: "${target.path}"),`
|
|
599
|
+
: ` .target(name: "${target.name}", dependencies: ${JSON.stringify((target.dependencies ?? []).map((dependency) => dependency.name))}, path: "${target.path}", ${target.exclude.length > 0 ? `exclude: ${JSON.stringify(target.exclude)}, ` : ''}${target.resources ? 'resources: [], ' : ''}${settings(target)}${libraries(target)}),`,
|
|
579
600
|
),
|
|
580
601
|
'])',
|
|
581
602
|
'',
|
|
@@ -590,6 +611,17 @@ function packageFiles(root: string): string[] {
|
|
|
590
611
|
return xcode ? xcode.files : sourceTreeFiles(canonicalRoot, canonicalRoot)
|
|
591
612
|
}
|
|
592
613
|
|
|
614
|
+
// remote dependencies are enumerated from peach's checkout cache, while app
|
|
615
|
+
// inputs retain their selected-project boundary and all symlink checks.
|
|
616
|
+
function readPackageFile(root: string, file: string, maxBytes: number): Buffer {
|
|
617
|
+
if (xcodeProjects.has(root)) {
|
|
618
|
+
const checkouts = remoteSwiftCheckouts(root)
|
|
619
|
+
if (file.startsWith(`${checkouts}${path.sep}`))
|
|
620
|
+
return readSwiftSourceFile(checkouts, file, maxBytes)
|
|
621
|
+
}
|
|
622
|
+
return readSwiftSourceFile(root, file, maxBytes)
|
|
623
|
+
}
|
|
624
|
+
|
|
593
625
|
// every input file under `dir`, which must stay inside `canonicalRoot`.
|
|
594
626
|
function sourceTreeFiles(dir: string, canonicalRoot: string): string[] {
|
|
595
627
|
const found: string[] = []
|
|
@@ -983,6 +1015,13 @@ export function buildSwiftBundleFiles(
|
|
|
983
1015
|
const disk = path.join(packagePath, ...file.split('/'))
|
|
984
1016
|
const bytes = readPackageFile(packagePath, disk, limits.resourceBytes)
|
|
985
1017
|
addFile(bundlePath === '.' ? base : `${bundlePath}/${base}`, bytes)
|
|
1018
|
+
if (base.endsWith('.xcstrings')) {
|
|
1019
|
+
for (const [name, table] of Object.entries(
|
|
1020
|
+
compileStringCatalog(bytes.toString('utf8'), base.slice(0, -10)),
|
|
1021
|
+
)) {
|
|
1022
|
+
addFile(bundlePath === '.' ? name : `${bundlePath}/${name}`, Buffer.from(table))
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
986
1025
|
}
|
|
987
1026
|
}
|
|
988
1027
|
return { files, bundles, watched }
|
|
@@ -1048,6 +1087,24 @@ export function sourceStamp(
|
|
|
1048
1087
|
return hash.digest('hex').slice(0, 16)
|
|
1049
1088
|
}
|
|
1050
1089
|
|
|
1090
|
+
// sourceStamp's inputs read by content and relative to the package, so
|
|
1091
|
+
// another process's build copy of the same sources stamps the same.
|
|
1092
|
+
export function sourceContentStamp(
|
|
1093
|
+
packagePath: string,
|
|
1094
|
+
moduleRootOverride?: string,
|
|
1095
|
+
): string {
|
|
1096
|
+
const hash = createHash('sha256')
|
|
1097
|
+
hash.update(JSON.stringify(xcodeProjects.get(packagePath)?.behavior ?? {}))
|
|
1098
|
+
const libraries = projects.get(packagePath)?.libraries
|
|
1099
|
+
if (libraries) hash.update(JSON.stringify(libraries))
|
|
1100
|
+
for (const file of [...new Set(packageFiles(packagePath))].sort()) {
|
|
1101
|
+
hash.update(path.relative(packagePath, file))
|
|
1102
|
+
hash.update(fs.readFileSync(file))
|
|
1103
|
+
}
|
|
1104
|
+
hash.update(moduleStamp(packagePath, moduleRootOverride, false))
|
|
1105
|
+
return hash.digest('hex').slice(0, 16)
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1051
1108
|
// the linked module's part of the source stamp
|
|
1052
1109
|
function moduleStamp(
|
|
1053
1110
|
packagePath: string,
|
|
@@ -1177,9 +1234,7 @@ function packageSnapshot(project: SwiftProject, entry: string): SwiftPackageSnap
|
|
|
1177
1234
|
.relative(project.packagePath, file)
|
|
1178
1235
|
.split(path.sep)
|
|
1179
1236
|
.join(path.posix.sep)
|
|
1180
|
-
return layout
|
|
1181
|
-
? xcodeInputKey(layout, file, relative)
|
|
1182
|
-
: relative
|
|
1237
|
+
return layout ? xcodeInputKey(layout, file, relative) : relative
|
|
1183
1238
|
}),
|
|
1184
1239
|
),
|
|
1185
1240
|
resources: buildSwiftResourceTable(project, '', files),
|
|
@@ -1304,13 +1359,20 @@ async function compile(
|
|
|
1304
1359
|
if (process.env.CONTRAST_SWIFT_BUILD_ROOT)
|
|
1305
1360
|
return process.env.CONTRAST_SWIFT_BUILD_ROOT
|
|
1306
1361
|
const resolvedPath = path.resolve(packagePath)
|
|
1362
|
+
// units of one app share a root so the module cache stays warm.
|
|
1363
|
+
// peach-expo-swift/<app>/<scope>/<package> shares <app>/<scope>, and
|
|
1364
|
+
// the older <app>/<package> layout shares <app>. the scope is this
|
|
1365
|
+
// process, so two servers do not compile into one tree.
|
|
1366
|
+
const parts = resolvedPath.split(path.sep)
|
|
1367
|
+
const expoAt = parts.lastIndexOf('peach-expo-swift')
|
|
1368
|
+
const scoped = expoAt >= 0 && parts.length >= expoAt + 4
|
|
1307
1369
|
const buildKeyPath =
|
|
1308
|
-
|
|
1309
|
-
?
|
|
1370
|
+
expoAt >= 0 && parts.length >= expoAt + 3
|
|
1371
|
+
? parts.slice(0, scoped ? expoAt + 3 : expoAt + 2).join(path.sep)
|
|
1310
1372
|
: resolvedPath
|
|
1311
1373
|
return path.join(
|
|
1312
|
-
|
|
1313
|
-
'
|
|
1374
|
+
cacheDir(),
|
|
1375
|
+
'swift-builds',
|
|
1314
1376
|
createHash('sha256')
|
|
1315
1377
|
.update(`${moduleRoot}\0${buildKeyPath}`)
|
|
1316
1378
|
.digest('hex')
|
|
@@ -1496,7 +1558,7 @@ async function compileRemote(
|
|
|
1496
1558
|
hosted?.authorization ?? (auth ? authHeaderValue(auth) : undefined)
|
|
1497
1559
|
const signal = AbortSignal.any([
|
|
1498
1560
|
...(ownerSignal ? [ownerSignal] : []),
|
|
1499
|
-
AbortSignal.timeout(
|
|
1561
|
+
AbortSignal.timeout(DEFAULT_SWIFT_COMPILE_BUILD_MS + 60_000),
|
|
1500
1562
|
])
|
|
1501
1563
|
const submit = httpSwiftCompileSubmit({
|
|
1502
1564
|
endpoint: origin,
|
package/src/swift-icu.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { existsSync, readFileSync } from 'node:fs'
|
|
|
4
4
|
import path from 'node:path'
|
|
5
5
|
import { promisify } from 'node:util'
|
|
6
6
|
import { gzip } from 'node:zlib'
|
|
7
|
+
import { swiftSdkOptions } from './swift-toolchain.ts'
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* the icu common data a swift artifact reserves and its host fills
|
|
@@ -49,15 +50,21 @@ function memo<T>(
|
|
|
49
50
|
|
|
50
51
|
/** the raw blob, for a harness that fills an artifact in node. */
|
|
51
52
|
export function swiftIcuData(toolchainBin: string, sdk: string): Promise<Buffer> {
|
|
52
|
-
return memo(raw,
|
|
53
|
+
return memo(raw, JSON.stringify([toolchainBin, sdk, swiftSdkOptions()]), () =>
|
|
54
|
+
load(toolchainBin, sdk),
|
|
55
|
+
)
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
/** the served form: gzipped and content-addressed. */
|
|
56
59
|
export function swiftIcuAsset(toolchainBin: string, sdk: string): Promise<SwiftIcuAsset> {
|
|
57
|
-
return memo(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
return memo(
|
|
61
|
+
assets,
|
|
62
|
+
JSON.stringify([toolchainBin, sdk, swiftSdkOptions()]),
|
|
63
|
+
async () => {
|
|
64
|
+
const zipped = await deflate(await swiftIcuData(toolchainBin, sdk))
|
|
65
|
+
return { sha256: createHash('sha256').update(zipped).digest('hex'), gzip: zipped }
|
|
66
|
+
},
|
|
67
|
+
)
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
async function load(toolchainBin: string, sdk: string): Promise<Buffer> {
|
|
@@ -66,12 +73,13 @@ async function load(toolchainBin: string, sdk: string): Promise<Buffer> {
|
|
|
66
73
|
// missing piece instead of shelling out to sdk configure.
|
|
67
74
|
if (!existsSync(swift))
|
|
68
75
|
throw new Error(`swift-icu: no swift at ${swift} for the ${sdk} SDK's icu data`)
|
|
69
|
-
const { stdout: listed } = await run(swift, ['sdk', 'list'])
|
|
76
|
+
const { stdout: listed } = await run(swift, ['sdk', 'list', ...swiftSdkOptions()])
|
|
70
77
|
if (!listed.split('\n').some((line) => line.trim() === sdk))
|
|
71
78
|
throw new Error(`swift-icu: ${sdk} is not installed for ${swift}`)
|
|
72
79
|
const { stdout } = await run(swift, [
|
|
73
80
|
'sdk',
|
|
74
81
|
'configure',
|
|
82
|
+
...swiftSdkOptions(),
|
|
75
83
|
'--show-configuration',
|
|
76
84
|
sdk,
|
|
77
85
|
'wasm32-unknown-wasip1',
|
package/src/swift-objc-sdk.ts
CHANGED
|
@@ -11,6 +11,129 @@ export const IOS_SDK_TARGET = 'arm64-apple-ios16.0-simulator'
|
|
|
11
11
|
|
|
12
12
|
/** the clang headers and module maps, by path under the sdk root. */
|
|
13
13
|
export const IOS_SDK_HEADERS: Record<string, string> = {
|
|
14
|
+
// darwin pointer and mach port identities used in public native headers.
|
|
15
|
+
'usr/include/pthread.h': `#pragma once
|
|
16
|
+
struct _opaque_pthread_t;
|
|
17
|
+
typedef struct _opaque_pthread_t *pthread_t;
|
|
18
|
+
`,
|
|
19
|
+
'usr/include/mach/mach_types.h': `#pragma once
|
|
20
|
+
#include <stdint.h>
|
|
21
|
+
typedef unsigned int natural_t;
|
|
22
|
+
typedef int integer_t;
|
|
23
|
+
typedef int vm_prot_t;
|
|
24
|
+
typedef integer_t cpu_type_t;
|
|
25
|
+
typedef integer_t cpu_subtype_t;
|
|
26
|
+
typedef natural_t *thread_state_t;
|
|
27
|
+
typedef int thread_state_flavor_t;
|
|
28
|
+
typedef natural_t mach_port_t;
|
|
29
|
+
typedef mach_port_t thread_t;
|
|
30
|
+
typedef thread_t thread_act_t;
|
|
31
|
+
typedef thread_act_t *thread_act_array_t;
|
|
32
|
+
typedef natural_t mach_msg_type_number_t;
|
|
33
|
+
`,
|
|
34
|
+
'usr/include/mach/mach.h': `#pragma once
|
|
35
|
+
#include <mach/mach_types.h>
|
|
36
|
+
`,
|
|
37
|
+
'usr/include/TargetConditionals.h': `#pragma once
|
|
38
|
+
#define TARGET_OS_IPHONE 1
|
|
39
|
+
#define TARGET_OS_IOS 1
|
|
40
|
+
#define TARGET_OS_SIMULATOR 1
|
|
41
|
+
#define TARGET_OS_OSX 0
|
|
42
|
+
#define TARGET_OS_MAC 1
|
|
43
|
+
#define TARGET_OS_TV 0
|
|
44
|
+
#define TARGET_OS_WATCH 0
|
|
45
|
+
#define TARGET_OS_VISION 0
|
|
46
|
+
#define TARGET_OS_MACCATALYST 0
|
|
47
|
+
#define TARGET_IPHONE_SIMULATOR 1
|
|
48
|
+
#define TARGET_CPU_ARM64 1
|
|
49
|
+
#define TARGET_CPU_X86_64 0
|
|
50
|
+
#define TARGET_RT_64_BIT 1
|
|
51
|
+
`,
|
|
52
|
+
'usr/include/stdlib.h': `#pragma once
|
|
53
|
+
#include <stddef.h>
|
|
54
|
+
void exit(int) __attribute__((noreturn));
|
|
55
|
+
void abort(void) __attribute__((noreturn));
|
|
56
|
+
void *malloc(size_t);
|
|
57
|
+
void free(void *);
|
|
58
|
+
`,
|
|
59
|
+
'usr/include/unistd.h': `#pragma once
|
|
60
|
+
#include <stdlib.h>
|
|
61
|
+
void _exit(int) __attribute__((noreturn));
|
|
62
|
+
`,
|
|
63
|
+
'usr/include/string.h': `#pragma once
|
|
64
|
+
#include <stddef.h>
|
|
65
|
+
size_t strlen(const char *);
|
|
66
|
+
char *strdup(const char *);
|
|
67
|
+
void *memcpy(void *, const void *, size_t);
|
|
68
|
+
void *memset(void *, int, size_t);
|
|
69
|
+
int strcmp(const char *, const char *);
|
|
70
|
+
`,
|
|
71
|
+
'usr/include/sys/types.h': `#pragma once
|
|
72
|
+
#include <time.h>
|
|
73
|
+
#include <stddef.h>
|
|
74
|
+
typedef long ssize_t;
|
|
75
|
+
`,
|
|
76
|
+
'usr/include/time.h': `#pragma once
|
|
77
|
+
typedef long time_t;
|
|
78
|
+
`,
|
|
79
|
+
'usr/include/dlfcn.h': `#pragma once
|
|
80
|
+
typedef struct dl_info {
|
|
81
|
+
const char *dli_fname;
|
|
82
|
+
void *dli_fbase;
|
|
83
|
+
const char *dli_sname;
|
|
84
|
+
void *dli_saddr;
|
|
85
|
+
} Dl_info;
|
|
86
|
+
`,
|
|
87
|
+
'usr/include/sys/ucontext.h': `#pragma once
|
|
88
|
+
#include <stdint.h>
|
|
89
|
+
#define _STRUCT_ARM_EXCEPTION_STATE64 struct __darwin_arm_exception_state64
|
|
90
|
+
_STRUCT_ARM_EXCEPTION_STATE64 { uint64_t __far; uint32_t __esr, __exception; };
|
|
91
|
+
#define _STRUCT_ARM_THREAD_STATE64 struct __darwin_arm_thread_state64
|
|
92
|
+
_STRUCT_ARM_THREAD_STATE64 {
|
|
93
|
+
uint64_t __x[29];
|
|
94
|
+
uint64_t __fp, __lr, __sp, __pc;
|
|
95
|
+
uint32_t __cpsr, __pad;
|
|
96
|
+
};
|
|
97
|
+
#define _STRUCT_ARM_NEON_STATE64 struct __darwin_arm_neon_state64
|
|
98
|
+
_STRUCT_ARM_NEON_STATE64 { unsigned __int128 __v[32]; uint32_t __fpsr, __fpcr; };
|
|
99
|
+
#define _STRUCT_MCONTEXT64 struct __darwin_mcontext64
|
|
100
|
+
_STRUCT_MCONTEXT64 {
|
|
101
|
+
_STRUCT_ARM_EXCEPTION_STATE64 __es;
|
|
102
|
+
_STRUCT_ARM_THREAD_STATE64 __ss;
|
|
103
|
+
_STRUCT_ARM_NEON_STATE64 __ns;
|
|
104
|
+
};
|
|
105
|
+
`,
|
|
106
|
+
'usr/include/mach-o/loader.h': `#pragma once
|
|
107
|
+
#include <stdint.h>
|
|
108
|
+
#include <mach/mach_types.h>
|
|
109
|
+
#define LC_SEGMENT_64 0x19
|
|
110
|
+
struct mach_header_64 {
|
|
111
|
+
uint32_t magic;
|
|
112
|
+
int32_t cputype, cpusubtype;
|
|
113
|
+
uint32_t filetype, ncmds, sizeofcmds, flags, reserved;
|
|
114
|
+
};
|
|
115
|
+
struct segment_command_64 {
|
|
116
|
+
uint32_t cmd, cmdsize;
|
|
117
|
+
char segname[16];
|
|
118
|
+
uint64_t vmaddr, vmsize, fileoff, filesize;
|
|
119
|
+
int32_t maxprot, initprot;
|
|
120
|
+
uint32_t nsects, flags;
|
|
121
|
+
};
|
|
122
|
+
struct section_64 {
|
|
123
|
+
char sectname[16], segname[16];
|
|
124
|
+
uint64_t addr, size;
|
|
125
|
+
uint32_t offset, align, reloff, nreloc, flags, reserved1, reserved2, reserved3;
|
|
126
|
+
};
|
|
127
|
+
`,
|
|
128
|
+
'usr/include/mach-o/nlist.h': `#pragma once
|
|
129
|
+
#include <stdint.h>
|
|
130
|
+
struct nlist_64 {
|
|
131
|
+
union { uint32_t n_strx; } n_un;
|
|
132
|
+
uint8_t n_type, n_sect;
|
|
133
|
+
uint16_t n_desc;
|
|
134
|
+
uint64_t n_value;
|
|
135
|
+
};
|
|
136
|
+
`,
|
|
14
137
|
'usr/include/module.modulemap': `module ObjectiveC [system] {
|
|
15
138
|
header "objc/NSObject.h"
|
|
16
139
|
export *
|
|
@@ -67,6 +190,10 @@ __attribute__((objc_root_class))
|
|
|
67
190
|
@end
|
|
68
191
|
@interface Protocol : NSObject
|
|
69
192
|
@end
|
|
193
|
+
`,
|
|
194
|
+
'System/Library/Frameworks/CoreFoundation.framework/Headers/CoreFoundation.h': `#pragma once
|
|
195
|
+
#import <Foundation/Foundation.h>
|
|
196
|
+
typedef const struct __attribute__((objc_bridge(NSString))) __CFString *CFStringRef;
|
|
70
197
|
`,
|
|
71
198
|
'System/Library/Frameworks/CoreGraphics.framework/Headers/CoreGraphics.h': `#pragma once
|
|
72
199
|
#include <stdint.h>
|
|
@@ -99,9 +226,15 @@ typedef struct __attribute__((objc_bridge(id))) CGColorSpace *CGColorSpaceRef;
|
|
|
99
226
|
#include <stddef.h>
|
|
100
227
|
#include <stdbool.h>
|
|
101
228
|
#include <stdarg.h>
|
|
229
|
+
#include <stdlib.h>
|
|
230
|
+
#include <string.h>
|
|
231
|
+
#include <time.h>
|
|
232
|
+
#include <TargetConditionals.h>
|
|
102
233
|
#import <objc/NSObject.h>
|
|
103
234
|
#import <CoreGraphics/CoreGraphics.h>
|
|
104
235
|
|
|
236
|
+
@class NSException;
|
|
237
|
+
typedef void NSUncaughtExceptionHandler(NSException *exception);
|
|
105
238
|
#define FOUNDATION_EXPORT extern
|
|
106
239
|
#define FOUNDATION_EXTERN extern
|
|
107
240
|
#define FOUNDATION_STATIC_INLINE static inline
|
|
@@ -237,16 +370,6 @@ typedef struct __attribute__((objc_bridge(id))) CGColorSpace *CGColorSpaceRef;
|
|
|
237
370
|
#define CF_IMPLICIT_BRIDGING_DISABLED _Pragma("clang arc_cf_code_audited end")
|
|
238
371
|
#define NS_NONATOMIC_IOSONLY nonatomic
|
|
239
372
|
#define NS_UNAVAILABLE_INIT
|
|
240
|
-
#define TARGET_OS_IPHONE 1
|
|
241
|
-
#define TARGET_OS_IOS 1
|
|
242
|
-
#define TARGET_OS_SIMULATOR 1
|
|
243
|
-
#define TARGET_OS_OSX 0
|
|
244
|
-
#define TARGET_OS_MAC 1
|
|
245
|
-
#define TARGET_OS_TV 0
|
|
246
|
-
#define TARGET_OS_WATCH 0
|
|
247
|
-
#define TARGET_OS_VISION 0
|
|
248
|
-
#define TARGET_OS_MACCATALYST 0
|
|
249
|
-
#define TARGET_IPHONE_SIMULATOR 1
|
|
250
373
|
#define NSIntegerMax LONG_MAX
|
|
251
374
|
#define NSIntegerMin LONG_MIN
|
|
252
375
|
#define NSUIntegerMax ULONG_MAX
|
|
@@ -26,6 +26,7 @@ export interface ObjcSurface {
|
|
|
26
26
|
module: string
|
|
27
27
|
modulemap: string
|
|
28
28
|
headers: string
|
|
29
|
+
dependencies?: { module: string; headers: string }[]
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
export interface ObjcView {
|
|
@@ -123,7 +124,7 @@ export function objcView(
|
|
|
123
124
|
const include = path.join(work, 'include')
|
|
124
125
|
const headersDir = framework
|
|
125
126
|
? path.join(frameworks, `${surface.module}.framework`, 'Headers')
|
|
126
|
-
: include
|
|
127
|
+
: path.join(include, surface.module)
|
|
127
128
|
const originals = new Map(
|
|
128
129
|
headerFiles(surface.headers).map((file) => [
|
|
129
130
|
file,
|
|
@@ -143,7 +144,22 @@ export function objcView(
|
|
|
143
144
|
path.join(frameworks, `${surface.module}.framework`, 'Modules', 'module.modulemap'),
|
|
144
145
|
)
|
|
145
146
|
} else {
|
|
146
|
-
fs.copyFileSync(surface.modulemap, path.join(
|
|
147
|
+
fs.copyFileSync(surface.modulemap, path.join(headersDir, 'module.modulemap'))
|
|
148
|
+
}
|
|
149
|
+
for (const dependency of surface.dependencies ?? []) {
|
|
150
|
+
const dir = path.join(include, dependency.module)
|
|
151
|
+
fs.mkdirSync(dir, { recursive: true })
|
|
152
|
+
for (const file of headerFiles(dependency.headers)) {
|
|
153
|
+
fs.mkdirSync(path.dirname(path.join(dir, file)), { recursive: true })
|
|
154
|
+
fs.copyFileSync(path.join(dependency.headers, file), path.join(dir, file))
|
|
155
|
+
}
|
|
156
|
+
const supplied = path.join(dependency.headers, 'module.modulemap')
|
|
157
|
+
fs.writeFileSync(
|
|
158
|
+
path.join(dir, 'module.modulemap'),
|
|
159
|
+
fs.existsSync(supplied)
|
|
160
|
+
? fs.readFileSync(supplied, 'utf8')
|
|
161
|
+
: `module ${dependency.module} { umbrella "." export * }\n`,
|
|
162
|
+
)
|
|
147
163
|
}
|
|
148
164
|
const stubs = path.join(work, 'stubs')
|
|
149
165
|
const stubIncludes = path.join(work, 'stub-include')
|
|
@@ -158,6 +174,12 @@ export function objcView(
|
|
|
158
174
|
frameworks,
|
|
159
175
|
'-I',
|
|
160
176
|
include,
|
|
177
|
+
'-I',
|
|
178
|
+
headersDir,
|
|
179
|
+
...(surface.dependencies ?? []).flatMap((dependency) => [
|
|
180
|
+
'-I',
|
|
181
|
+
path.join(include, dependency.module),
|
|
182
|
+
]),
|
|
161
183
|
'-F',
|
|
162
184
|
stubs,
|
|
163
185
|
'-I',
|
|
@@ -300,7 +322,7 @@ export function objcView(
|
|
|
300
322
|
}
|
|
301
323
|
if (!progress || round === ROUNDS)
|
|
302
324
|
throw new Error(
|
|
303
|
-
`its headers do not import as Swift: ${[...new Set(errors.map((match) => match[4]!))].slice(0,
|
|
325
|
+
`its headers do not import as Swift: ${[...new Set(errors.map((match) => match[4]!))].slice(0, 10).join('; ')}`,
|
|
304
326
|
)
|
|
305
327
|
if (missing.size > 0) declareMissing()
|
|
306
328
|
}
|