-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdevicectl.ts
More file actions
98 lines (82 loc) · 2.7 KB
/
devicectl.ts
File metadata and controls
98 lines (82 loc) · 2.7 KB
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
import {exec, SubProcess} from 'teen_process';
import _ from 'lodash';
import logger from '@appium/logger';
import type {ExecuteOptions, ExecuteResult} from './types';
import * as processMixins from './mixins/process';
import * as infoMixins from './mixins/info';
import * as copyMixins from './mixins/copy';
import * as listMixins from './mixins/list';
const XCRUN = 'xcrun';
const LOG_TAG = 'Devicectl';
/**
* Node.js wrapper around Apple's devicectl tool
*
* This class provides methods to interact with iOS devices using the devicectl command-line tool.
* It requires Xcode 15+ and iOS 17+ to function properly.
*
*/
export class Devicectl {
/** The unique device identifier */
public readonly udid: string;
/**
* Creates a new Devicectl instance
*
* @param udid - The unique device identifier
*/
constructor(udid: string) {
this.udid = udid;
}
/**
* Executes a devicectl command
*
* @param subcommand - The devicectl subcommand to execute
* @param opts - Execution options
* @returns Promise that resolves to the command result
*/
async execute<T extends ExecuteOptions>(
subcommand: string[],
opts?: T,
): Promise<ExecuteResult<T>> {
const {
logStdout = false,
asynchronous = false,
asJson = true,
noDevice = false,
subcommandOptions,
timeout,
} = opts ?? {};
const finalArgs = ['devicectl', ...subcommand, ...(noDevice ? [] : ['--device', this.udid])];
if (subcommandOptions && !_.isEmpty(subcommandOptions)) {
finalArgs.push(
...(Array.isArray(subcommandOptions) ? subcommandOptions : [subcommandOptions]),
);
}
if (asJson) {
finalArgs.push('--quiet', '--json-output', '-');
}
const cmdStr = [XCRUN, ...finalArgs].map((arg) => `"${arg}"`).join(' ');
logger.debug(LOG_TAG, `Executing ${cmdStr}`);
try {
if (asynchronous) {
const result = new SubProcess(XCRUN, finalArgs);
await result.start(0);
return result as ExecuteResult<T>;
}
const result = await exec(XCRUN, finalArgs, ...(_.isNumber(timeout) ? [{timeout}] : []));
if (logStdout) {
logger.debug(LOG_TAG, `Command output: ${result.stdout}`);
}
return result as ExecuteResult<T>;
} catch (e: any) {
throw new Error(`'${cmdStr}' failed. Original error: ${e.stderr || e.stdout || e.message}`);
}
}
sendMemoryWarning = processMixins.sendMemoryWarning;
sendSignalToProcess = processMixins.sendSignalToProcess;
launchApp = processMixins.launchApp;
listProcesses = infoMixins.listProcesses;
listApps = infoMixins.listApps;
listFiles = copyMixins.listFiles;
pullFile = copyMixins.pullFile;
listDevices = listMixins.listDevices;
}