ranger-compiler 3.2.0 → 3.4.0
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/CHANGELOG.md +2482 -0
- package/LICENSE +28 -0
- package/LICENSE-MIT +21 -0
- package/README.md +1650 -1895
- package/dist/Lang.rgr +10946 -5852
- package/dist/README.md +3 -2
- package/dist/api.d.ts +1157 -29
- package/dist/api.js +66623 -38073
- package/dist/lib/ACEEditor.rgr +2 -0
- package/dist/lib/Ajax.rgr +2 -0
- package/dist/lib/CmdParams.rgr +2 -0
- package/dist/lib/Crypto.rgr +2 -0
- package/dist/lib/DOMLib.rgr +2 -0
- package/dist/lib/Engine3D.rgr +2 -0
- package/dist/lib/ImmutableVector.rgr +2 -0
- package/dist/lib/IndexedDB.rgr +2 -0
- package/dist/lib/IsoDate/DateMath.rgr +2 -0
- package/dist/lib/IsoDate/IsoCalendar.rgr +2 -0
- package/dist/lib/IsoDate/IsoDateParse.rgr +2 -0
- package/dist/lib/IsoDateLib.rgr +2 -0
- package/dist/lib/JSON.rgr +4906 -48
- package/dist/lib/JinxProcess.rgr +2 -0
- package/dist/lib/RangerProcess.rgr +2 -0
- package/dist/lib/Regex/RegexMatch.rgr +2 -0
- package/dist/lib/RegexLib.rgr +2 -0
- package/dist/lib/SQL.rgr +2 -0
- package/dist/lib/ServiceLib.rgr +2 -0
- package/dist/lib/Shell.rgr +326 -0
- package/dist/lib/Storage.rgr +2 -0
- package/dist/lib/Time.rgr +2 -0
- package/dist/lib/Timers.rgr +2 -0
- package/dist/lib/TypedArrays.rgr +2 -0
- package/dist/lib/ViewLib.rgr +2 -0
- package/dist/lib/WebLib.rgr +2 -0
- package/dist/lib/WebServerLib.rgr +2 -0
- package/dist/lib/apple/AppleAppBuilder.rgr +572 -0
- package/dist/lib/apple/AppleAppSpec.rgr +201 -0
- package/dist/lib/apple/AppleDevice.rgr +295 -0
- package/dist/lib/apple/AppleDeviceDoctor.rgr +453 -0
- package/dist/lib/apple/AppleSigning.rgr +379 -0
- package/dist/lib/apple/AppleSimulator.rgr +248 -0
- package/dist/lib/apple/AppleTarget.rgr +185 -0
- package/dist/lib/apple/AppleToolchain.rgr +458 -0
- package/dist/lib/apple/README.md +311 -0
- package/dist/lib/apple/apple_test.rgr +669 -0
- package/dist/lib/core/README.md +251 -0
- package/dist/lib/core/RgBase.rgr +313 -0
- package/dist/lib/core/RgNum.rgr +653 -0
- package/dist/lib/core/RgText.rgr +680 -0
- package/dist/lib/core/RgU32.rgr +309 -0
- package/dist/lib/ranger-dir.rgr +2 -0
- package/dist/lib/shell_test.rgr +193 -0
- package/dist/lib/stdlib.rgr +1176 -665
- package/dist/lib/stdops.rgr +2 -0
- package/dist/package.json +1 -1
- package/dist/rgrc.js +72955 -40753
- package/dist/stdops.rgr +2 -0
- package/package.json +1121 -339
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
; SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
; =============================================================================
|
|
4
|
+
; AppleTarget.rgr -- what "build it for an iPhone" actually has to name.
|
|
5
|
+
; =============================================================================
|
|
6
|
+
;
|
|
7
|
+
; Xcode hides four separate decisions behind one scheme pop-up, and a build
|
|
8
|
+
; driven from the command line has to make all four itself:
|
|
9
|
+
;
|
|
10
|
+
; the SDK iphoneos, iphonesimulator, watchos, watchsimulator. This is
|
|
11
|
+
; what `xcrun --sdk NAME --show-sdk-path` resolves and what
|
|
12
|
+
; swiftc compiles against.
|
|
13
|
+
; the triple arm64-apple-ios15.0-simulator. The architecture, the
|
|
14
|
+
; platform, the DEPLOYMENT TARGET and, for a simulator, the
|
|
15
|
+
; `-simulator` environment. Leave the environment off and the
|
|
16
|
+
; compiler silently builds for a real device, which links but
|
|
17
|
+
; will not run on the simulator.
|
|
18
|
+
; the families iPhone, iPad, or both -- one number list in Info.plist, and
|
|
19
|
+
; the only difference between "an iPhone app" and "an iPad
|
|
20
|
+
; app" once the binary exists. A watch app is its own family
|
|
21
|
+
; and its own kind of bundle.
|
|
22
|
+
; signing a simulator build is signed ad hoc (identity "-"), which
|
|
23
|
+
; needs nothing installed. A device build needs a real
|
|
24
|
+
; identity and a provisioning profile, and this file only
|
|
25
|
+
; carries the name of them.
|
|
26
|
+
;
|
|
27
|
+
; None of this needs Xcode the application. It needs the toolchain Xcode (or
|
|
28
|
+
; the Command Line Tools) installs, which is what `xcrun` is for.
|
|
29
|
+
; =============================================================================
|
|
30
|
+
|
|
31
|
+
; The `UIDeviceFamily` numbers, which is the vocabulary Info.plist uses for
|
|
32
|
+
; "which device is this for".
|
|
33
|
+
class AppleDeviceFamily {
|
|
34
|
+
sfn iphone:int () {
|
|
35
|
+
return 1
|
|
36
|
+
}
|
|
37
|
+
sfn ipad:int () {
|
|
38
|
+
return 2
|
|
39
|
+
}
|
|
40
|
+
sfn tv:int () {
|
|
41
|
+
return 3
|
|
42
|
+
}
|
|
43
|
+
sfn watch:int () {
|
|
44
|
+
return 4
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
; One buildable combination: an SDK, a triple, and what the resulting bundle
|
|
49
|
+
; says it runs on.
|
|
50
|
+
class AppleTarget {
|
|
51
|
+
|
|
52
|
+
; A short name for this combination, used in log lines and build paths:
|
|
53
|
+
; "ios-simulator", "ios-device", "watchos-simulator", "watchos-device".
|
|
54
|
+
def key:string ""
|
|
55
|
+
; What `xcrun --sdk` is given.
|
|
56
|
+
def sdk:string ""
|
|
57
|
+
; The platform part of the triple: "ios" or "watchos".
|
|
58
|
+
def platform:string ""
|
|
59
|
+
; The deployment target, which goes INTO the triple, not beside it.
|
|
60
|
+
def minVersion:string ""
|
|
61
|
+
; "arm64" or "x86_64". A simulator target is built for whatever the Mac
|
|
62
|
+
; running the build is, because the simulator runs native code.
|
|
63
|
+
def arch:string "arm64"
|
|
64
|
+
def isSimulator:boolean true
|
|
65
|
+
; UIDeviceFamily. Two entries is a universal iPhone/iPad app.
|
|
66
|
+
def families:[int]
|
|
67
|
+
; The codesigning identity. "-" is ad hoc, which is all a simulator wants.
|
|
68
|
+
def signIdentity:string "-"
|
|
69
|
+
|
|
70
|
+
Constructor () {
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
; iPhone and iPad, on the simulator. The default, because it is the one
|
|
74
|
+
; combination that needs nothing but an installed Xcode -- no developer
|
|
75
|
+
; account, no device, no provisioning profile.
|
|
76
|
+
sfn iosSimulator:AppleTarget (arch:string) {
|
|
77
|
+
def t:AppleTarget (new AppleTarget)
|
|
78
|
+
t.key = "ios-simulator"
|
|
79
|
+
t.sdk = "iphonesimulator"
|
|
80
|
+
t.platform = "ios"
|
|
81
|
+
t.minVersion = "15.0"
|
|
82
|
+
t.arch = arch
|
|
83
|
+
t.isSimulator = true
|
|
84
|
+
t.families = ([] _:int ( 1 2 ))
|
|
85
|
+
t.signIdentity = "-"
|
|
86
|
+
return t
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
; A real iPhone or iPad. Needs a signing identity and a provisioning
|
|
90
|
+
; profile; everything else about the build is the same.
|
|
91
|
+
sfn iosDevice:AppleTarget (identity:string) {
|
|
92
|
+
def t:AppleTarget (new AppleTarget)
|
|
93
|
+
t.key = "ios-device"
|
|
94
|
+
t.sdk = "iphoneos"
|
|
95
|
+
t.platform = "ios"
|
|
96
|
+
t.minVersion = "15.0"
|
|
97
|
+
t.arch = "arm64"
|
|
98
|
+
t.isSimulator = false
|
|
99
|
+
t.families = ([] _:int ( 1 2 ))
|
|
100
|
+
t.signIdentity = identity
|
|
101
|
+
return t
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
; The watch, on the simulator. A standalone watchOS app -- no paired iPhone
|
|
105
|
+
; app, which is what watchOS 6 and later allow and what makes a watch build
|
|
106
|
+
; from the command line reasonable at all.
|
|
107
|
+
sfn watchSimulator:AppleTarget (arch:string) {
|
|
108
|
+
def t:AppleTarget (new AppleTarget)
|
|
109
|
+
t.key = "watchos-simulator"
|
|
110
|
+
t.sdk = "watchsimulator"
|
|
111
|
+
t.platform = "watchos"
|
|
112
|
+
t.minVersion = "9.0"
|
|
113
|
+
t.arch = arch
|
|
114
|
+
t.isSimulator = true
|
|
115
|
+
t.families = ([] _:int ( 4 ))
|
|
116
|
+
t.signIdentity = "-"
|
|
117
|
+
return t
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
sfn watchDevice:AppleTarget (identity:string) {
|
|
121
|
+
def t:AppleTarget (new AppleTarget)
|
|
122
|
+
t.key = "watchos-device"
|
|
123
|
+
t.sdk = "watchos"
|
|
124
|
+
t.platform = "watchos"
|
|
125
|
+
t.minVersion = "9.0"
|
|
126
|
+
t.arch = "arm64"
|
|
127
|
+
t.isSimulator = false
|
|
128
|
+
t.families = ([] _:int ( 4 ))
|
|
129
|
+
t.signIdentity = identity
|
|
130
|
+
return t
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
; Only iPhone, or only iPad. The binary does not change; the bundle's claim
|
|
134
|
+
; about itself does, and that is what the home screen and the simulator
|
|
135
|
+
; read.
|
|
136
|
+
fn onlyPhone:void () {
|
|
137
|
+
families = ([] _:int ( 1 ))
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
fn onlyPad:void () {
|
|
141
|
+
families = ([] _:int ( 2 ))
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
; The triple swiftc is given. The deployment target is IN it -- there is no
|
|
145
|
+
; separate flag for it on this path -- and the `-simulator` environment is
|
|
146
|
+
; what keeps a simulator build from being a device build that happens to
|
|
147
|
+
; link.
|
|
148
|
+
fn swiftTriple:string () {
|
|
149
|
+
def base:string (arch + "-apple-" + platform + minVersion)
|
|
150
|
+
if isSimulator {
|
|
151
|
+
return (base + "-simulator")
|
|
152
|
+
}
|
|
153
|
+
return base
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
fn isWatch:boolean () {
|
|
157
|
+
return (platform == "watchos")
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
; Signing a simulator bundle ad hoc is not ceremony: an unsigned bundle is
|
|
161
|
+
; rejected by the simulator on recent macOS, and "-" needs nothing
|
|
162
|
+
; installed to satisfy it.
|
|
163
|
+
fn isAdHocSigned:boolean () {
|
|
164
|
+
return (signIdentity == "-")
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
fn describe:string () {
|
|
168
|
+
def fam:[string]
|
|
169
|
+
for families f:int i {
|
|
170
|
+
if (f == 1) {
|
|
171
|
+
push fam "iPhone"
|
|
172
|
+
}
|
|
173
|
+
if (f == 2) {
|
|
174
|
+
push fam "iPad"
|
|
175
|
+
}
|
|
176
|
+
if (f == 3) {
|
|
177
|
+
push fam "Apple TV"
|
|
178
|
+
}
|
|
179
|
+
if (f == 4) {
|
|
180
|
+
push fam "Apple Watch"
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return (key + " (" + (this.swiftTriple()) + ", sdk " + sdk + ", " + (join fam " + ") + ")")
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
; SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
; =============================================================================
|
|
4
|
+
; AppleToolchain.rgr -- Apple's command line tools, as methods.
|
|
5
|
+
; =============================================================================
|
|
6
|
+
;
|
|
7
|
+
; Everything here goes through `xcrun`, which is the one program that knows
|
|
8
|
+
; where the rest of them are. `xcrun swiftc` is not the same as `swiftc`: the
|
|
9
|
+
; first resolves inside the selected developer directory and against the SDK
|
|
10
|
+
; you name, the second is whichever Swift is on PATH and knows nothing about
|
|
11
|
+
; iOS. Building for a device with the wrong one of those is the single most
|
|
12
|
+
; common way a command line iOS build goes wrong, so nothing here calls a tool
|
|
13
|
+
; directly.
|
|
14
|
+
;
|
|
15
|
+
; What this needs installed: Xcode, or the Command Line Tools plus the platform
|
|
16
|
+
; SDKs. Nothing here opens Xcode, and nothing here needs a .xcodeproj.
|
|
17
|
+
;
|
|
18
|
+
; Every call goes through `Shell`, so a driver can be run dry -- the commands
|
|
19
|
+
; are then recorded rather than executed, which is what makes an Apple build
|
|
20
|
+
; pipeline testable on a machine that is not a Mac.
|
|
21
|
+
; =============================================================================
|
|
22
|
+
|
|
23
|
+
Import "../Shell.rgr"
|
|
24
|
+
Import "AppleTarget.rgr"
|
|
25
|
+
Import "AppleSimulator.rgr"
|
|
26
|
+
Import "AppleDevice.rgr"
|
|
27
|
+
|
|
28
|
+
class AppleToolchain {
|
|
29
|
+
|
|
30
|
+
def sh:Shell
|
|
31
|
+
; Cached answers. `xcrun --show-sdk-path` costs about a tenth of a second
|
|
32
|
+
; and a build asks for the same SDK several times.
|
|
33
|
+
def sdkPaths:[string:string]
|
|
34
|
+
def sdkVersions:[string:string]
|
|
35
|
+
|
|
36
|
+
Constructor (shell:Shell) {
|
|
37
|
+
sh = shell
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
; Is there a toolchain here at all? Asked first, so "no Xcode installed" is
|
|
41
|
+
; one clear sentence rather than a swiftc failure nobody can read.
|
|
42
|
+
fn isAvailable:boolean () {
|
|
43
|
+
return (sh.isInstalled("xcrun"))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
; Which Xcode (or Command Line Tools) is selected. `xcode-select -p`.
|
|
47
|
+
fn developerDir:string () {
|
|
48
|
+
; Every argument vector in this file is BUILT rather than written as
|
|
49
|
+
; an inline literal: a one-element literal is flattened to its element
|
|
50
|
+
; on Rust (ISSUES.md #84), and any literal is lost when the call
|
|
51
|
+
; taking it is immediately dereferenced (#85). A build driver that only
|
|
52
|
+
; compiled on Node would be a poor advertisement for a cross-language
|
|
53
|
+
; compiler; this one is checked on seven targets.
|
|
54
|
+
def argv:[string]
|
|
55
|
+
push argv "-p"
|
|
56
|
+
return (sh.text("xcode-select" argv))
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
; The Swift the toolchain will actually compile with, as one line.
|
|
60
|
+
fn swiftVersion:string () {
|
|
61
|
+
def argv:[string]
|
|
62
|
+
push argv "swift"
|
|
63
|
+
push argv "--version"
|
|
64
|
+
def res:ShellResult (sh.capture("xcrun" argv))
|
|
65
|
+
if (res.failed()) {
|
|
66
|
+
return ""
|
|
67
|
+
}
|
|
68
|
+
return (res.outFirstLine())
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
; The Mac this build is running on. A simulator runs NATIVE code, so an
|
|
72
|
+
; Apple Silicon Mac builds simulator binaries for arm64 and an Intel Mac
|
|
73
|
+
; builds them for x86_64 -- getting this from the machine rather than from
|
|
74
|
+
; a constant is why a simulator build works on both.
|
|
75
|
+
fn hostArch:string () {
|
|
76
|
+
def argv:[string]
|
|
77
|
+
push argv "-m"
|
|
78
|
+
def arch:string (sh.text("uname" argv))
|
|
79
|
+
if ((strlen arch) == 0) {
|
|
80
|
+
return "arm64"
|
|
81
|
+
}
|
|
82
|
+
if (arch == "x86_64") {
|
|
83
|
+
return "x86_64"
|
|
84
|
+
}
|
|
85
|
+
return "arm64"
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
; The same question as `sdkPath`, with the failure kept. `sdkPath` answers
|
|
89
|
+
; "" for anything that went wrong, which is the right shape for a build and
|
|
90
|
+
; the wrong one for a diagnostic: an Xcode whose licence has not been
|
|
91
|
+
; accepted, one whose platforms have not been downloaded and one that is not
|
|
92
|
+
; there all answer "" and have three different fixes. xcrun says which on
|
|
93
|
+
; stderr, so a report has to be able to see it.
|
|
94
|
+
fn probeSdk:ShellResult (sdk:string) {
|
|
95
|
+
def argv:[string]
|
|
96
|
+
push argv "--sdk"
|
|
97
|
+
push argv sdk
|
|
98
|
+
push argv "--show-sdk-path"
|
|
99
|
+
return (sh.capture("xcrun" argv))
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
fn probeSwift:ShellResult () {
|
|
103
|
+
def argv:[string]
|
|
104
|
+
push argv "swift"
|
|
105
|
+
push argv "--version"
|
|
106
|
+
return (sh.capture("xcrun" argv))
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
; Where the SDK lives. swiftc is given this path, not the SDK name.
|
|
110
|
+
fn sdkPath:string (sdk:string) {
|
|
111
|
+
if (has sdkPaths sdk) {
|
|
112
|
+
return (unwrap (get sdkPaths sdk))
|
|
113
|
+
}
|
|
114
|
+
def argv:[string]
|
|
115
|
+
push argv "--sdk"
|
|
116
|
+
push argv sdk
|
|
117
|
+
push argv "--show-sdk-path"
|
|
118
|
+
def p:string (sh.text("xcrun" argv))
|
|
119
|
+
set sdkPaths sdk p
|
|
120
|
+
return p
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
; The SDK version, which is not the same as the deployment target: the SDK
|
|
124
|
+
; is what you build AGAINST, the deployment target is the oldest OS the
|
|
125
|
+
; result runs on.
|
|
126
|
+
fn sdkVersion:string (sdk:string) {
|
|
127
|
+
if (has sdkVersions sdk) {
|
|
128
|
+
return (unwrap (get sdkVersions sdk))
|
|
129
|
+
}
|
|
130
|
+
def argv:[string]
|
|
131
|
+
push argv "--sdk"
|
|
132
|
+
push argv sdk
|
|
133
|
+
push argv "--show-sdk-version"
|
|
134
|
+
def v:string (sh.text("xcrun" argv))
|
|
135
|
+
set sdkVersions sdk v
|
|
136
|
+
return v
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
; Is this platform's SDK installed? An Xcode with the iOS platform but not
|
|
140
|
+
; the watchOS one is an ordinary installation, not a broken one, so a watch
|
|
141
|
+
; build says so instead of failing inside swiftc.
|
|
142
|
+
fn hasSdk:boolean (sdk:string) {
|
|
143
|
+
return ((strlen (this.sdkPath(sdk))) > 0)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
; --- the simulators -------------------------------------------------------
|
|
147
|
+
|
|
148
|
+
fn listSimulators:[AppleSimulator] () {
|
|
149
|
+
def argv:[string]
|
|
150
|
+
push argv "simctl"
|
|
151
|
+
push argv "list"
|
|
152
|
+
push argv "devices"
|
|
153
|
+
push argv "available"
|
|
154
|
+
def res:ShellResult (sh.capture("xcrun" argv))
|
|
155
|
+
if (res.failed()) {
|
|
156
|
+
def none:[AppleSimulator]
|
|
157
|
+
return none
|
|
158
|
+
}
|
|
159
|
+
return (AppleSimulatorList.parse(res.out))
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
; The simulator to install onto: on the platform this target builds for,
|
|
163
|
+
; preferring one that is already booted, and preferring `nameWanted` when
|
|
164
|
+
; the caller named something.
|
|
165
|
+
fn pickSimulator@(optional):AppleSimulator (target:AppleTarget nameWanted:string) {
|
|
166
|
+
def all:[AppleSimulator] (this.listSimulators())
|
|
167
|
+
def prefix:string "iOS"
|
|
168
|
+
if (target.isWatch()) {
|
|
169
|
+
prefix = "watchOS"
|
|
170
|
+
}
|
|
171
|
+
def onPlatform:[AppleSimulator] (AppleSimulatorList.onPlatform(all prefix))
|
|
172
|
+
return (AppleSimulatorList.pick(onPlatform nameWanted))
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
; Boot it if it is not booted. Booting one that is already up is an error
|
|
176
|
+
; from simctl and a no-op in fact, so the state is checked rather than the
|
|
177
|
+
; failure ignored.
|
|
178
|
+
fn bootSimulator:boolean (dev:AppleSimulator) {
|
|
179
|
+
if (dev.isBooted()) {
|
|
180
|
+
return true
|
|
181
|
+
}
|
|
182
|
+
def argv:[string]
|
|
183
|
+
push argv "simctl"
|
|
184
|
+
push argv "boot"
|
|
185
|
+
push argv dev.udid
|
|
186
|
+
def res:ShellResult (sh.capture("xcrun" argv))
|
|
187
|
+
if (res.ok()) {
|
|
188
|
+
return true
|
|
189
|
+
}
|
|
190
|
+
; "Unable to boot device in current state: Booted" is a race with
|
|
191
|
+
; something else having booted it, which is success as far as this is
|
|
192
|
+
; concerned.
|
|
193
|
+
if ((indexOf res.err "current state: Booted") >= 0) {
|
|
194
|
+
return true
|
|
195
|
+
}
|
|
196
|
+
return false
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
; Bring the Simulator application to the front. Without this the device is
|
|
200
|
+
; running and there is no window, which looks exactly like a build that did
|
|
201
|
+
; nothing.
|
|
202
|
+
fn openSimulatorUi:boolean () {
|
|
203
|
+
def argv:[string]
|
|
204
|
+
push argv "-a"
|
|
205
|
+
push argv "Simulator"
|
|
206
|
+
def res:ShellResult (sh.capture("open" argv))
|
|
207
|
+
return (res.ok())
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
; Wait until the device is finished booting. Installing into a device that
|
|
211
|
+
; is still starting fails intermittently, which is the worst kind of
|
|
212
|
+
; failure to debug.
|
|
213
|
+
fn waitForBoot:boolean (dev:AppleSimulator) {
|
|
214
|
+
def argv:[string]
|
|
215
|
+
push argv "simctl"
|
|
216
|
+
push argv "bootstatus"
|
|
217
|
+
push argv dev.udid
|
|
218
|
+
def res:ShellResult (sh.capture("xcrun" argv))
|
|
219
|
+
return (res.ok())
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
fn installApp:ShellResult (dev:AppleSimulator appPath:string) {
|
|
223
|
+
def argv:[string]
|
|
224
|
+
push argv "simctl"
|
|
225
|
+
push argv "install"
|
|
226
|
+
push argv dev.udid
|
|
227
|
+
push argv appPath
|
|
228
|
+
return (sh.capture("xcrun" argv))
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
fn launchApp:ShellResult (dev:AppleSimulator bundleId:string) {
|
|
232
|
+
def argv:[string]
|
|
233
|
+
push argv "simctl"
|
|
234
|
+
push argv "launch"
|
|
235
|
+
push argv "--terminate-running-process"
|
|
236
|
+
push argv dev.udid
|
|
237
|
+
push argv bundleId
|
|
238
|
+
return (sh.capture("xcrun" argv))
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
; The app's own log, filtered to this bundle. The watch and the phone both
|
|
242
|
+
; write here, and it is the only way to see a print() from inside a
|
|
243
|
+
; simulator without attaching a debugger.
|
|
244
|
+
fn streamLog:ShellResult (dev:AppleSimulator bundleId:string) {
|
|
245
|
+
def predicate:string ("subsystem CONTAINS \"" + bundleId + "\" OR process CONTAINS \"" + bundleId + "\"")
|
|
246
|
+
def argv:[string]
|
|
247
|
+
push argv "simctl"
|
|
248
|
+
push argv "spawn"
|
|
249
|
+
push argv dev.udid
|
|
250
|
+
push argv "log"
|
|
251
|
+
push argv "stream"
|
|
252
|
+
push argv "--level"
|
|
253
|
+
push argv "debug"
|
|
254
|
+
push argv "--predicate"
|
|
255
|
+
push argv predicate
|
|
256
|
+
return (sh.run("xcrun" argv))
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
; --- real devices ---------------------------------------------------------
|
|
260
|
+
|
|
261
|
+
; Attached iPhones and iPads, as raw text. `devicectl` ships with Xcode 15
|
|
262
|
+
; and later; older toolchains need a third party installer, which this does
|
|
263
|
+
; not pretend to wrap.
|
|
264
|
+
fn hasDeviceCtl:boolean () {
|
|
265
|
+
def argv:[string]
|
|
266
|
+
push argv "devicectl"
|
|
267
|
+
push argv "--version"
|
|
268
|
+
def res:ShellResult (sh.capture("xcrun" argv))
|
|
269
|
+
return (res.ok())
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
; The iPhones and iPads that are plugged in, parsed.
|
|
273
|
+
fn listConnectedDevices:[AppleDeviceInfo] () {
|
|
274
|
+
def res:ShellResult (this.listDevices())
|
|
275
|
+
if (res.failed()) {
|
|
276
|
+
def none:[AppleDeviceInfo]
|
|
277
|
+
return none
|
|
278
|
+
}
|
|
279
|
+
return (AppleDeviceList.parse(res.out))
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
; The one to install onto: connected, and matching `nameWanted` when the
|
|
283
|
+
; caller named something.
|
|
284
|
+
fn pickDevice@(optional):AppleDeviceInfo (nameWanted:string) {
|
|
285
|
+
def all:[AppleDeviceInfo] (this.listConnectedDevices())
|
|
286
|
+
return (AppleDeviceList.pick(all nameWanted))
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
fn listDevices:ShellResult () {
|
|
290
|
+
def argv:[string]
|
|
291
|
+
push argv "devicectl"
|
|
292
|
+
push argv "list"
|
|
293
|
+
push argv "devices"
|
|
294
|
+
return (sh.capture("xcrun" argv))
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
; Start it on the device. `devicectl` needs the bundle id, not the path --
|
|
298
|
+
; the app is already installed by this point -- and `--console` keeps the
|
|
299
|
+
; process attached so its output lands here, which is what a test build on
|
|
300
|
+
; a cable is for.
|
|
301
|
+
fn launchOnDevice:ShellResult (udid:string bundleId:string attach:boolean) {
|
|
302
|
+
def argv:[string]
|
|
303
|
+
push argv "devicectl"
|
|
304
|
+
push argv "device"
|
|
305
|
+
push argv "process"
|
|
306
|
+
push argv "launch"
|
|
307
|
+
push argv "--device"
|
|
308
|
+
push argv udid
|
|
309
|
+
if attach {
|
|
310
|
+
push argv "--console"
|
|
311
|
+
} {
|
|
312
|
+
push argv "--terminate-existing"
|
|
313
|
+
}
|
|
314
|
+
push argv bundleId
|
|
315
|
+
if attach {
|
|
316
|
+
return (sh.run("xcrun" argv))
|
|
317
|
+
}
|
|
318
|
+
return (sh.capture("xcrun" argv))
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
fn installOnDevice:ShellResult (udid:string appPath:string) {
|
|
322
|
+
def argv:[string]
|
|
323
|
+
push argv "devicectl"
|
|
324
|
+
push argv "device"
|
|
325
|
+
push argv "install"
|
|
326
|
+
push argv "app"
|
|
327
|
+
push argv "--device"
|
|
328
|
+
push argv udid
|
|
329
|
+
push argv appPath
|
|
330
|
+
return (sh.capture("xcrun" argv))
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
; Everything the device will say about itself. This is also the cheapest
|
|
334
|
+
; way to ask whether a device can be TALKED to at all: it raises the tunnel
|
|
335
|
+
; if one is needed, so a failure here is a real connection failure and not
|
|
336
|
+
; a stale line in a listing.
|
|
337
|
+
fn deviceDetails:ShellResult (udid:string) {
|
|
338
|
+
def argv:[string]
|
|
339
|
+
push argv "devicectl"
|
|
340
|
+
push argv "device"
|
|
341
|
+
push argv "info"
|
|
342
|
+
push argv "details"
|
|
343
|
+
push argv "--device"
|
|
344
|
+
push argv udid
|
|
345
|
+
return (sh.capture("xcrun" argv))
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
; The apps already installed. Listing them needs the developer disk image,
|
|
349
|
+
; so asking is how the DDI gets mounted on a device that has none: devicectl
|
|
350
|
+
; personalises and mounts it, and the answer arrives a few seconds later.
|
|
351
|
+
; A build that asks this first therefore fixes the commonest reason an
|
|
352
|
+
; install is refused, rather than reporting it.
|
|
353
|
+
fn listInstalledApps:ShellResult (udid:string) {
|
|
354
|
+
def argv:[string]
|
|
355
|
+
push argv "devicectl"
|
|
356
|
+
push argv "device"
|
|
357
|
+
push argv "info"
|
|
358
|
+
push argv "apps"
|
|
359
|
+
push argv "--device"
|
|
360
|
+
push argv udid
|
|
361
|
+
return (sh.capture("xcrun" argv))
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
; What the USB bus has on it, as raw text. Asked only when devicectl lists
|
|
365
|
+
; NOTHING, because it separates "no cable" from "a cable and no pairing" --
|
|
366
|
+
; and because it is the one question here that a broken CoreDevice cannot
|
|
367
|
+
; get in the way of.
|
|
368
|
+
fn usbDeviceText:string () {
|
|
369
|
+
def argv:[string]
|
|
370
|
+
push argv "SPUSBDataType"
|
|
371
|
+
def res:ShellResult (sh.capture("system_profiler" argv))
|
|
372
|
+
if (res.failed()) {
|
|
373
|
+
return ""
|
|
374
|
+
}
|
|
375
|
+
return res.out
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
; --- signing --------------------------------------------------------------
|
|
379
|
+
|
|
380
|
+
; The identities available for signing a device build. Ad hoc signing needs
|
|
381
|
+
; none of them, which is why a simulator build works on a machine with no
|
|
382
|
+
; developer account at all.
|
|
383
|
+
fn signingIdentities:ShellResult () {
|
|
384
|
+
def argv:[string]
|
|
385
|
+
push argv "find-identity"
|
|
386
|
+
push argv "-v"
|
|
387
|
+
push argv "-p"
|
|
388
|
+
push argv "codesigning"
|
|
389
|
+
return (sh.capture("security" argv))
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
fn codesign:ShellResult (identity:string bundlePath:string entitlements:string) {
|
|
393
|
+
def argv:[string]
|
|
394
|
+
push argv "--force"
|
|
395
|
+
push argv "--sign"
|
|
396
|
+
push argv identity
|
|
397
|
+
if ((strlen entitlements) > 0) {
|
|
398
|
+
push argv "--entitlements"
|
|
399
|
+
push argv entitlements
|
|
400
|
+
}
|
|
401
|
+
push argv "--timestamp=none"
|
|
402
|
+
push argv bundlePath
|
|
403
|
+
return (sh.capture("codesign" argv))
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
; --- turning a plist into what the device wants ---------------------------
|
|
407
|
+
|
|
408
|
+
; iOS reads a binary plist perfectly well as XML, so this is optional --
|
|
409
|
+
; but converting also VALIDATES, which turns an unparseable plist into a
|
|
410
|
+
; build error instead of an app that silently refuses to install.
|
|
411
|
+
fn convertPlistToBinary:ShellResult (plistPath:string) {
|
|
412
|
+
def argv:[string]
|
|
413
|
+
push argv "-convert"
|
|
414
|
+
push argv "binary1"
|
|
415
|
+
push argv plistPath
|
|
416
|
+
return (sh.capture("plutil" argv))
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
fn lintPlist:ShellResult (plistPath:string) {
|
|
420
|
+
def argv:[string]
|
|
421
|
+
push argv "-lint"
|
|
422
|
+
push argv plistPath
|
|
423
|
+
return (sh.capture("plutil" argv))
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
; --- asset catalogs -------------------------------------------------------
|
|
427
|
+
|
|
428
|
+
; Compile an .xcassets into the Assets.car an app icon has to be in. Only
|
|
429
|
+
; called when the caller has a catalog; an app with no icon builds and runs
|
|
430
|
+
; without one.
|
|
431
|
+
fn compileAssets:ShellResult (catalog:string outDir:string target:AppleTarget) {
|
|
432
|
+
def platformName:string "iphonesimulator"
|
|
433
|
+
if (target.isWatch()) {
|
|
434
|
+
platformName = "watchsimulator"
|
|
435
|
+
if (target.isSimulator == false) {
|
|
436
|
+
platformName = "watchos"
|
|
437
|
+
}
|
|
438
|
+
} {
|
|
439
|
+
if (target.isSimulator == false) {
|
|
440
|
+
platformName = "iphoneos"
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
def argv:[string]
|
|
444
|
+
push argv "actool"
|
|
445
|
+
push argv catalog
|
|
446
|
+
push argv "--compile"
|
|
447
|
+
push argv outDir
|
|
448
|
+
push argv "--platform"
|
|
449
|
+
push argv platformName
|
|
450
|
+
push argv "--minimum-deployment-target"
|
|
451
|
+
push argv target.minVersion
|
|
452
|
+
push argv "--app-icon"
|
|
453
|
+
push argv "AppIcon"
|
|
454
|
+
push argv "--output-partial-info-plist"
|
|
455
|
+
push argv (outDir + "/assetcatalog.plist")
|
|
456
|
+
return (sh.capture("xcrun" argv))
|
|
457
|
+
}
|
|
458
|
+
}
|