appium-xcuitest-driver 7.22.0 → 7.23.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 +12 -0
- package/build/lib/commands/certificate.js +4 -4
- package/build/lib/commands/certificate.js.map +1 -1
- package/build/lib/commands/log.d.ts.map +1 -1
- package/build/lib/commands/log.js +2 -1
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/memory.js +1 -1
- package/build/lib/commands/memory.js.map +1 -1
- package/build/lib/commands/pcap.d.ts.map +1 -1
- package/build/lib/commands/pcap.js +3 -11
- package/build/lib/commands/pcap.js.map +1 -1
- package/build/lib/commands/performance.d.ts.map +1 -1
- package/build/lib/commands/performance.js +3 -5
- package/build/lib/commands/performance.js.map +1 -1
- package/build/lib/commands/recordscreen.d.ts.map +1 -1
- package/build/lib/commands/recordscreen.js +8 -9
- package/build/lib/commands/recordscreen.js.map +1 -1
- package/build/lib/device-log/helpers.d.ts +4 -0
- package/build/lib/device-log/helpers.d.ts.map +1 -1
- package/build/lib/device-log/helpers.js +22 -0
- package/build/lib/device-log/helpers.js.map +1 -1
- package/build/lib/device-log/ios-crash-log.d.ts +30 -38
- package/build/lib/device-log/ios-crash-log.d.ts.map +1 -1
- package/build/lib/device-log/ios-crash-log.js +97 -100
- package/build/lib/device-log/ios-crash-log.js.map +1 -1
- package/build/lib/device-log/ios-log.d.ts +1 -1
- package/build/lib/device-log/ios-log.d.ts.map +1 -1
- package/build/lib/device-log/ios-log.js +2 -1
- package/build/lib/device-log/ios-log.js.map +1 -1
- package/build/lib/driver.d.ts +4 -2
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +2 -2
- package/build/lib/driver.js.map +1 -1
- package/build/lib/real-device-clients/base-device-client.d.ts +22 -0
- package/build/lib/real-device-clients/base-device-client.d.ts.map +1 -0
- package/build/lib/real-device-clients/base-device-client.js +13 -0
- package/build/lib/real-device-clients/base-device-client.js.map +1 -0
- package/build/lib/real-device-clients/devicectl.d.ts.map +1 -0
- package/build/lib/real-device-clients/devicectl.js.map +1 -0
- package/build/lib/real-device-clients/py-ios-device-client.d.ts +21 -0
- package/build/lib/real-device-clients/py-ios-device-client.d.ts.map +1 -0
- package/build/lib/{py-ios-device-client.js → real-device-clients/py-ios-device-client.js} +53 -84
- package/build/lib/real-device-clients/py-ios-device-client.js.map +1 -0
- package/build/lib/real-device.d.ts +1 -1
- package/build/lib/real-device.d.ts.map +1 -1
- package/build/lib/real-device.js +1 -1
- package/build/lib/real-device.js.map +1 -1
- package/lib/commands/certificate.js +1 -1
- package/lib/commands/log.js +2 -1
- package/lib/commands/memory.js +1 -1
- package/lib/commands/pcap.js +3 -8
- package/lib/commands/performance.js +3 -5
- package/lib/commands/recordscreen.js +7 -8
- package/lib/device-log/helpers.ts +27 -0
- package/lib/device-log/ios-crash-log.ts +167 -0
- package/lib/device-log/ios-log.ts +2 -1
- package/lib/driver.js +1 -1
- package/lib/real-device-clients/base-device-client.ts +34 -0
- package/lib/real-device-clients/py-ios-device-client.ts +149 -0
- package/lib/real-device.js +1 -1
- package/npm-shrinkwrap.json +9 -9
- package/package.json +1 -1
- package/build/lib/devicectl.d.ts.map +0 -1
- package/build/lib/devicectl.js.map +0 -1
- package/build/lib/py-ios-device-client.d.ts +0 -76
- package/build/lib/py-ios-device-client.d.ts.map +0 -1
- package/build/lib/py-ios-device-client.js.map +0 -1
- package/lib/device-log/ios-crash-log.js +0 -146
- package/lib/py-ios-device-client.js +0 -167
- /package/build/lib/{devicectl.d.ts → real-device-clients/devicectl.d.ts} +0 -0
- /package/build/lib/{devicectl.js → real-device-clients/devicectl.js} +0 -0
- /package/lib/{devicectl.js → real-device-clients/devicectl.js} +0 -0
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
export default Pyidevice;
|
|
2
|
-
export class Pyidevice {
|
|
3
|
-
/**
|
|
4
|
-
* @param {string} udid
|
|
5
|
-
*/
|
|
6
|
-
constructor(udid: string);
|
|
7
|
-
udid: string;
|
|
8
|
-
binaryPath: string | null;
|
|
9
|
-
/**
|
|
10
|
-
* @param {boolean} isStrict
|
|
11
|
-
* @return {Promise<boolean>}
|
|
12
|
-
*/
|
|
13
|
-
assertExists(isStrict?: boolean): Promise<boolean>;
|
|
14
|
-
/**
|
|
15
|
-
* @typedef {Object} ExecuteOptions
|
|
16
|
-
* @property {string} cwd
|
|
17
|
-
* @property {string?} format [json]
|
|
18
|
-
* @property {boolean} logStdout [false]
|
|
19
|
-
* @property {boolean} asynchronous [false]
|
|
20
|
-
*/
|
|
21
|
-
/**
|
|
22
|
-
* @param {string[]} args
|
|
23
|
-
* @param {Partial<ExecuteOptions>} opts
|
|
24
|
-
* @return {Promise<import('teen_process').TeenProcessExecResult|import('teen_process').SubProcess>}
|
|
25
|
-
*/
|
|
26
|
-
execute(args: string[], opts?: Partial<{
|
|
27
|
-
cwd: string;
|
|
28
|
-
/**
|
|
29
|
-
* [json]
|
|
30
|
-
*/
|
|
31
|
-
format: string | null;
|
|
32
|
-
/**
|
|
33
|
-
* [false]
|
|
34
|
-
*/
|
|
35
|
-
logStdout: boolean;
|
|
36
|
-
/**
|
|
37
|
-
* [false]
|
|
38
|
-
*/
|
|
39
|
-
asynchronous: boolean;
|
|
40
|
-
}>): Promise<import("teen_process").TeenProcessExecResult<any> | import("teen_process").SubProcess>;
|
|
41
|
-
/**
|
|
42
|
-
* @return {Promise<object>}
|
|
43
|
-
*/
|
|
44
|
-
listProfiles(): Promise<object>;
|
|
45
|
-
/**
|
|
46
|
-
*
|
|
47
|
-
* @param { {profilePath?: string, payload: string|Buffer} } opts
|
|
48
|
-
* @privateRemarks The error below seems to suggest that `payload` can be undefined, but the code suggests otherwise
|
|
49
|
-
*/
|
|
50
|
-
installProfile(opts: {
|
|
51
|
-
profilePath?: string;
|
|
52
|
-
payload: string | Buffer;
|
|
53
|
-
}): Promise<void>;
|
|
54
|
-
/**
|
|
55
|
-
*
|
|
56
|
-
* @param {string} name
|
|
57
|
-
* @returns {Promise<string>}
|
|
58
|
-
*/
|
|
59
|
-
removeProfile(name: string): Promise<string>;
|
|
60
|
-
/**
|
|
61
|
-
* @returns {Promise<object>}
|
|
62
|
-
*/
|
|
63
|
-
listCrashes(): Promise<object>;
|
|
64
|
-
/**
|
|
65
|
-
* @param {string} name
|
|
66
|
-
* @param {string} dstFolder
|
|
67
|
-
* @returns {Promise<void>}
|
|
68
|
-
*/
|
|
69
|
-
exportCrash(name: string, dstFolder: string): Promise<void>;
|
|
70
|
-
/**
|
|
71
|
-
* @param {string} dstFile
|
|
72
|
-
*/
|
|
73
|
-
collectPcap(dstFile: string): Promise<SubProcess | import("teen_process").TeenProcessExecResult<any>>;
|
|
74
|
-
}
|
|
75
|
-
import { SubProcess } from 'teen_process';
|
|
76
|
-
//# sourceMappingURL=py-ios-device-client.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"py-ios-device-client.d.ts","sourceRoot":"","sources":["../../lib/py-ios-device-client.js"],"names":[],"mappings":";AASA;IACE;;OAEG;IACH,kBAFW,MAAM,EAKhB;IAFC,aAAgB;IAChB,0BAAsB;IAGxB;;;OAGG;IACH,wBAHW,OAAO,GACN,OAAO,CAAC,OAAO,CAAC,CAoB3B;IAED;;;;;;OAMG;IAEH;;;;OAIG;IACH,cAJW,MAAM,EAAE,SACR,OAAO;aARJ,MAAM;;;;gBACN,MAAM,OAAC;;;;mBACP,OAAO;;;;sBACP,OAAO;MAKa,GACtB,OAAO,CAAC,iDAA4C,GAAC,OAAO,cAAc,EAAE,UAAU,CAAC,CA2BlG;IAED;;OAEG;IACH,gBAFY,OAAO,CAAC,MAAM,CAAC,CAO1B;IAED;;;;OAIG;IACH,qBAHY;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,GAAC,MAAM,CAAA;KAAC,iBAyBzD;IAED;;;;OAIG;IACH,oBAHW,MAAM,GACJ,OAAO,CAAC,MAAM,CAAC,CAM3B;IAED;;OAEG;IACH,eAFa,OAAO,CAAC,MAAM,CAAC,CAO3B;IAED;;;;OAIG;IACH,kBAJW,MAAM,aACN,MAAM,GACJ,OAAO,CAAC,IAAI,CAAC,CAQzB;IACD;;OAEG;IACH,qBAFW,MAAM,2EAOhB;CACF;2BAnK8B,cAAc"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"py-ios-device-client.js","sourceRoot":"","sources":["../../lib/py-ios-device-client.js"],"names":[],"mappings":"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"}
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import {fs, tempDir} from 'appium/support';
|
|
2
|
-
import B from 'bluebird';
|
|
3
|
-
import log from '../logger';
|
|
4
|
-
import {utilities} from 'appium-ios-device';
|
|
5
|
-
import path from 'path';
|
|
6
|
-
import _ from 'lodash';
|
|
7
|
-
import Pyidevice from '../py-ios-device-client';
|
|
8
|
-
|
|
9
|
-
const REAL_DEVICE_MAGIC = '3620bbb0-fb9f-4b62-a668-896f2edc4d88';
|
|
10
|
-
const MAGIC_SEP = '/';
|
|
11
|
-
// The file format has been changed from '.crash' to '.ips' since Monterey.
|
|
12
|
-
const CRASH_REPORTS_GLOB_PATTERN = '**/*.@(crash|ips)';
|
|
13
|
-
|
|
14
|
-
class IOSCrashLog {
|
|
15
|
-
constructor(opts = {}) {
|
|
16
|
-
this.udid = opts.udid;
|
|
17
|
-
this.pyideviceClient = this.udid ? new Pyidevice(this.udid) : null;
|
|
18
|
-
const root = process.env.HOME || '/';
|
|
19
|
-
const logDir = opts.udid
|
|
20
|
-
? path.resolve(root, 'Library', 'Logs', 'CrashReporter', 'MobileDevice')
|
|
21
|
-
: path.resolve(root, 'Library', 'Logs', 'DiagnosticReports');
|
|
22
|
-
this.logDir = logDir || path.resolve(root, 'Library', 'Logs', 'DiagnosticReports');
|
|
23
|
-
this.prevLogs = [];
|
|
24
|
-
this.logsSinceLastRequest = [];
|
|
25
|
-
this.phoneName = null;
|
|
26
|
-
this.sim = opts.sim;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* @returns {Promise<string[]>}
|
|
31
|
-
*/
|
|
32
|
-
async _gatherFromRealDevice() {
|
|
33
|
-
if (await this.pyideviceClient?.assertExists(false)) {
|
|
34
|
-
return (await /** @type {Pyidevice} */ (this.pyideviceClient).listCrashes()).map(
|
|
35
|
-
(x) => `${REAL_DEVICE_MAGIC}${MAGIC_SEP}${x}`,
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
let crashLogsRoot = this.logDir;
|
|
40
|
-
if (this.udid) {
|
|
41
|
-
this.phoneName = this.phoneName || (await utilities.getDeviceName(this.udid));
|
|
42
|
-
crashLogsRoot = path.resolve(crashLogsRoot, this.phoneName);
|
|
43
|
-
}
|
|
44
|
-
if (!(await fs.exists(crashLogsRoot))) {
|
|
45
|
-
log.debug(`Crash reports root '${crashLogsRoot}' does not exist. Got nothing to gather.`);
|
|
46
|
-
return [];
|
|
47
|
-
}
|
|
48
|
-
return await fs.glob(CRASH_REPORTS_GLOB_PATTERN, {
|
|
49
|
-
cwd: crashLogsRoot,
|
|
50
|
-
absolute: true,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* @returns {Promise<string[]>}
|
|
56
|
-
*/
|
|
57
|
-
async _gatherFromSimulator() {
|
|
58
|
-
if (!(await fs.exists(this.logDir))) {
|
|
59
|
-
log.debug(`Crash reports root '${this.logDir}' does not exist. Got nothing to gather.`);
|
|
60
|
-
return [];
|
|
61
|
-
}
|
|
62
|
-
const foundFiles = await fs.glob(CRASH_REPORTS_GLOB_PATTERN, {
|
|
63
|
-
cwd: this.logDir,
|
|
64
|
-
absolute: true,
|
|
65
|
-
});
|
|
66
|
-
// For Simulator only include files, that contain current UDID
|
|
67
|
-
return await B.filter(foundFiles, async (x) => {
|
|
68
|
-
try {
|
|
69
|
-
const content = await fs.readFile(x, 'utf8');
|
|
70
|
-
return content.toUpperCase().includes(this.sim.udid.toUpperCase());
|
|
71
|
-
} catch (err) {
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* @returns {Promise<string[]>}
|
|
79
|
-
*/
|
|
80
|
-
async getCrashes() {
|
|
81
|
-
return this.udid ? await this._gatherFromRealDevice() : await this._gatherFromSimulator();
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* @returns {Promise<void>}
|
|
86
|
-
*/
|
|
87
|
-
async startCapture() {
|
|
88
|
-
this.prevLogs = await this.getCrashes();
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* @returns {Promise<void>}
|
|
93
|
-
*/
|
|
94
|
-
async stopCapture() {
|
|
95
|
-
// needed for consistent API with other logs
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* @returns {Promise<import('../commands/types').LogEntry[]>}
|
|
100
|
-
*/
|
|
101
|
-
async getLogs() {
|
|
102
|
-
let crashFiles = await this.getCrashes();
|
|
103
|
-
let diff = _.difference(crashFiles, this.prevLogs, this.logsSinceLastRequest);
|
|
104
|
-
this.logsSinceLastRequest = _.union(this.logsSinceLastRequest, diff);
|
|
105
|
-
return await this.filesToJSON(diff);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* @param {string[]} paths
|
|
110
|
-
* @returns {Promise<import('../commands/types').LogEntry[]>}
|
|
111
|
-
*/
|
|
112
|
-
async filesToJSON(paths) {
|
|
113
|
-
const tmpRoot = await tempDir.openDir();
|
|
114
|
-
try {
|
|
115
|
-
return /** @type {import('../commands/types').LogEntry[]} */ ((
|
|
116
|
-
await B.map(paths, async (fullPath) => {
|
|
117
|
-
if (_.includes(fullPath, REAL_DEVICE_MAGIC)) {
|
|
118
|
-
const fileName = /** @type {string} */ (_.last(fullPath.split(MAGIC_SEP)));
|
|
119
|
-
try {
|
|
120
|
-
// @ts-expect-error If pyideviceClient is not defined, then the exception will be caught below
|
|
121
|
-
await this.pyideviceClient.exportCrash(fileName, tmpRoot);
|
|
122
|
-
} catch (e) {
|
|
123
|
-
log.warn(
|
|
124
|
-
`Cannot export the crash report '${fileName}'. Skipping it. ` +
|
|
125
|
-
`Original error: ${e.message}`,
|
|
126
|
-
);
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
fullPath = path.join(tmpRoot, fileName);
|
|
130
|
-
}
|
|
131
|
-
const stat = await fs.stat(fullPath);
|
|
132
|
-
return {
|
|
133
|
-
timestamp: stat.ctime.getTime(),
|
|
134
|
-
level: 'ALL',
|
|
135
|
-
message: await fs.readFile(fullPath, 'utf8'),
|
|
136
|
-
};
|
|
137
|
-
})
|
|
138
|
-
).filter(Boolean));
|
|
139
|
-
} finally {
|
|
140
|
-
await fs.rimraf(tmpRoot);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export {IOSCrashLog};
|
|
146
|
-
export default IOSCrashLog;
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import {exec, SubProcess} from 'teen_process';
|
|
2
|
-
import {fs, util, tempDir} from 'appium/support';
|
|
3
|
-
import log from './logger';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
|
|
6
|
-
// https://github.com/YueChen-C/py-ios-device
|
|
7
|
-
|
|
8
|
-
const BINARY_NAME = 'pyidevice';
|
|
9
|
-
|
|
10
|
-
class Pyidevice {
|
|
11
|
-
/**
|
|
12
|
-
* @param {string} udid
|
|
13
|
-
*/
|
|
14
|
-
constructor(udid) {
|
|
15
|
-
this.udid = udid;
|
|
16
|
-
this.binaryPath = null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* @param {boolean} isStrict
|
|
21
|
-
* @return {Promise<boolean>}
|
|
22
|
-
*/
|
|
23
|
-
async assertExists(isStrict = true) {
|
|
24
|
-
if (this.binaryPath) {
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
this.binaryPath = await fs.which(BINARY_NAME);
|
|
30
|
-
return true;
|
|
31
|
-
} catch (e) {
|
|
32
|
-
if (isStrict) {
|
|
33
|
-
throw new Error(
|
|
34
|
-
`${BINARY_NAME} binary cannot be found in PATH. ` +
|
|
35
|
-
`Please make sure it is installed. Visit https://github.com/YueChen-C/py-ios-device for ` +
|
|
36
|
-
`more details.`,
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* @typedef {Object} ExecuteOptions
|
|
45
|
-
* @property {string} cwd
|
|
46
|
-
* @property {string?} format [json]
|
|
47
|
-
* @property {boolean} logStdout [false]
|
|
48
|
-
* @property {boolean} asynchronous [false]
|
|
49
|
-
*/
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* @param {string[]} args
|
|
53
|
-
* @param {Partial<ExecuteOptions>} opts
|
|
54
|
-
* @return {Promise<import('teen_process').TeenProcessExecResult|import('teen_process').SubProcess>}
|
|
55
|
-
*/
|
|
56
|
-
async execute(args, opts = {}) {
|
|
57
|
-
await this.assertExists();
|
|
58
|
-
const {cwd, format = 'json', logStdout = false, asynchronous = false} = opts;
|
|
59
|
-
|
|
60
|
-
const finalArgs = [...args, '--udid', this.udid, '--network'];
|
|
61
|
-
if (format) {
|
|
62
|
-
finalArgs.push('--format', format);
|
|
63
|
-
}
|
|
64
|
-
const binaryPath = /** @type {string} */ (this.binaryPath);
|
|
65
|
-
const cmdStr = util.quote([binaryPath, ...finalArgs]);
|
|
66
|
-
log.debug(`Executing ${cmdStr}`);
|
|
67
|
-
try {
|
|
68
|
-
if (asynchronous) {
|
|
69
|
-
const result = new SubProcess(binaryPath, finalArgs, {cwd});
|
|
70
|
-
await result.start(0);
|
|
71
|
-
return result;
|
|
72
|
-
}
|
|
73
|
-
const result = await exec(binaryPath, finalArgs, {cwd});
|
|
74
|
-
if (logStdout) {
|
|
75
|
-
log.debug(`Command output: ${result.stdout}`);
|
|
76
|
-
}
|
|
77
|
-
return result;
|
|
78
|
-
} catch (e) {
|
|
79
|
-
throw new Error(`'${cmdStr}' failed. Original error: ${e.stderr || e.stdout || e.message}`);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* @return {Promise<object>}
|
|
85
|
-
*/
|
|
86
|
-
async listProfiles() {
|
|
87
|
-
const {stdout} = /** @type {import('teen_process').TeenProcessExecResult} */ (
|
|
88
|
-
await this.execute(['profiles', 'list'])
|
|
89
|
-
);
|
|
90
|
-
return JSON.parse(stdout);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
*
|
|
95
|
-
* @param { {profilePath?: string, payload: string|Buffer} } opts
|
|
96
|
-
* @privateRemarks The error below seems to suggest that `payload` can be undefined, but the code suggests otherwise
|
|
97
|
-
*/
|
|
98
|
-
async installProfile(opts) {
|
|
99
|
-
const {profilePath, payload} = opts ?? {};
|
|
100
|
-
if (!profilePath && !payload) {
|
|
101
|
-
throw new Error('Either the full path to the profile or its payload must be provided');
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
let tmpRoot;
|
|
105
|
-
let srcPath = profilePath;
|
|
106
|
-
try {
|
|
107
|
-
if (!srcPath) {
|
|
108
|
-
tmpRoot = await tempDir.openDir();
|
|
109
|
-
srcPath = path.join(tmpRoot, 'cert.pem');
|
|
110
|
-
await fs.writeFile(srcPath, payload, 'utf8');
|
|
111
|
-
}
|
|
112
|
-
await this.execute(['profiles', 'install', '--path', srcPath], {
|
|
113
|
-
logStdout: true,
|
|
114
|
-
});
|
|
115
|
-
} finally {
|
|
116
|
-
if (tmpRoot) {
|
|
117
|
-
await fs.rimraf(tmpRoot);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
*
|
|
124
|
-
* @param {string} name
|
|
125
|
-
* @returns {Promise<string>}
|
|
126
|
-
*/
|
|
127
|
-
async removeProfile(name) {
|
|
128
|
-
return /** @type {import('teen_process').TeenProcessExecResult} */ (
|
|
129
|
-
await this.execute(['profiles', 'remove', '--name', name], {logStdout: true})
|
|
130
|
-
).stdout;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* @returns {Promise<object>}
|
|
135
|
-
*/
|
|
136
|
-
async listCrashes() {
|
|
137
|
-
const {stdout} = /** @type {import('teen_process').TeenProcessExecResult} */ (
|
|
138
|
-
await this.execute(['crash', 'list'])
|
|
139
|
-
);
|
|
140
|
-
return JSON.parse(stdout.replace(/'/g, '"')).filter((x) => !['.', '..'].includes(x));
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* @param {string} name
|
|
145
|
-
* @param {string} dstFolder
|
|
146
|
-
* @returns {Promise<void>}
|
|
147
|
-
*/
|
|
148
|
-
async exportCrash(name, dstFolder) {
|
|
149
|
-
await this.execute(['crash', 'export', '--name', name], {
|
|
150
|
-
logStdout: true,
|
|
151
|
-
// The tool exports crash reports to the current working dir
|
|
152
|
-
cwd: dstFolder,
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* @param {string} dstFile
|
|
157
|
-
*/
|
|
158
|
-
async collectPcap(dstFile) {
|
|
159
|
-
return await this.execute(['pcapd', dstFile], {
|
|
160
|
-
format: null,
|
|
161
|
-
asynchronous: true,
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export {Pyidevice};
|
|
167
|
-
export default Pyidevice;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|