-
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathsimctl.ts
154 lines (125 loc) · 4.65 KB
/
simctl.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import childProcess = require("./child-process");
import * as child_process from "child_process";
import errors = require("./errors");
import options = require("./options");
import * as _ from "lodash";
export class Simctl implements ISimctl {
public launch(deviceId: string, appIdentifier: string): string {
let args: string[] = [];
if (options.waitForDebugger) {
args.push("-w");
}
args = args.concat([deviceId, appIdentifier]);
if (options.args) {
let applicationArgs = options.args.trim().split(/\s+/);
_.each(applicationArgs, (arg: string) => args.push(arg));
}
let result = this.simctlExec("launch", args);
if (options.waitForDebugger) {
console.log(`${appIdentifier}: ${result}`);
}
return result;
}
public terminate(deviceId: string, appIdentifier: string): string {
return this.simctlExec("terminate", [deviceId, appIdentifier]);
}
public install(deviceId: string, applicationPath: string): void {
this.simctlExec("install", [deviceId, applicationPath]);
}
public uninstall(deviceId: string, appIdentifier: string, opts?: any): void {
this.simctlExec("uninstall", [deviceId, appIdentifier], opts);
}
public notifyPost(deviceId: string, notification: string): void {
this.simctlExec("notify_post", [deviceId, notification]);
}
public getAppContainer(deviceId: string, appIdentifier: string): string {
try {
return this.simctlExec("get_app_container", [deviceId, appIdentifier]);
} catch (e) {
if (e.message.indexOf("No such file or directory") > -1) {
return null;
}
throw e;
}
}
public getDevices(): IDevice[] {
let rawDevices = this.simctlExec("list", ["devices"]);
// expect to get a listing like
// -- iOS 8.1 --
// iPhone 4s (3CA6E7DD-220E-45E5-B716-1E992B3A429C) (Shutdown)
// ...
// -- iOS 8.2 --
// iPhone 4s (A99FFFC3-8E19-4DCF-B585-7D9D46B4C16E) (Shutdown)
// ...
// so, get the `-- iOS X.X --` line to find the sdk (X.X)
// and the rest of the listing in order to later find the devices
let deviceSectionRegex = /-- (iOS) (.+) --(\n .+)*/mg;
let match = deviceSectionRegex.exec(rawDevices);
let matches: any[] = [];
// make an entry for each sdk version
while (match !== null) {
matches.push(match);
match = deviceSectionRegex.exec(rawDevices);
}
if (matches.length < 1) {
errors.fail('Could not find device section. ' + match);
}
// get all the devices for each sdk
let devices: IDevice[] = [];
for (match of matches) {
let sdk: string = match[2];
// split the full match into lines and remove the first
for (let line of match[0].split('\n').slice(1)) {
// a line is something like
// iPhone 4s (A99FFFC3-8E19-4DCF-B585-7D9D46B4C16E) (Shutdown)
// iPad Air 2 (9696A8ED-3020-49FC-90D6-DAFD29A0EA8D) (Shutdown)
// iPad Pro (9.7 inch) (7FF984D4-0755-432D-BE0E-6EB44F0489CB) (Shutdown)
// iPad Pro (12.9 inch) (F02012C8-6D4D-46FF-90D7-5DF90EF579E8) (Booted)
// retrieve:
// iPhone 4s
// A99FFFC3-8E19-4DCF-B585-7D9D46B4C16E
// Shutdown
let lineRegex = /^\s+(.*?)\s+\(([0-9A-F]{8}(?:-[0-9A-F]{4}){3}-[0-9A-F]{12})\)\s+\((.*?)\)(\s+\((?:.*?)\))?/;
let lineMatch = lineRegex.exec(line);
if (lineMatch === null) {
errors.fail('Could not match line. ' + line);
}
let available = lineMatch[4];
if (available === null || available === undefined) {
devices.push({
name: lineMatch[1],
id: lineMatch[2],
fullId: "com.apple.CoreSimulator.SimDeviceType." + lineMatch[1],
runtimeVersion: sdk,
state: lineMatch[3]
});
}
}
}
return devices;
}
public getLog(deviceId: string, predicate?: string): child_process.ChildProcess {
let predicateArgs: string[] = [];
if (predicate) {
predicateArgs = ["--predicate", predicate];
}
return this.simctlSpawn("spawn", [deviceId, "log", "stream", "--style", "syslog"].concat(predicateArgs));
}
private simctlExec(command: string, args: string[], opts?: any): string {
const result = childProcess.spawnSync("xcrun", ["simctl", command].concat(args), opts);
if (result) {
if (result.signal) {
// In some cases, sending Ctrl + C (SIGINT) is handled by the simctl itself and spawnSync finishes, but the SIGINT does not stop current process.
// In order to ensure the same signal is sent to the caller (CLI for example), send the signal manually:
process.send(result.signal);
}
if (result.stdout) {
return result.stdout.toString().trim();
}
}
return '';
}
private simctlSpawn(command: string, args: string[], opts?: child_process.SpawnOptions): child_process.ChildProcess {
return child_process.spawn("xcrun", ["simctl", command].concat(args), opts);
}
}