@appium/support 7.1.0 → 7.2.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/build/lib/console.d.ts +2 -2
- package/build/lib/console.d.ts.map +1 -1
- package/build/lib/console.js +4 -5
- package/build/lib/console.js.map +1 -1
- package/build/lib/doctor.d.ts +6 -6
- package/build/lib/doctor.d.ts.map +1 -1
- package/build/lib/doctor.js +7 -7
- package/build/lib/doctor.js.map +1 -1
- package/build/lib/env.d.ts +12 -5
- package/build/lib/env.d.ts.map +1 -1
- package/build/lib/env.js +5 -5
- package/build/lib/env.js.map +1 -1
- package/build/lib/fs.d.ts.map +1 -1
- package/build/lib/fs.js +11 -14
- package/build/lib/fs.js.map +1 -1
- package/build/lib/image-util.d.ts.map +1 -1
- package/build/lib/image-util.js +1 -1
- package/build/lib/image-util.js.map +1 -1
- package/build/lib/index.d.ts +1 -1
- package/build/lib/index.d.ts.map +1 -1
- package/build/lib/logging.d.ts.map +1 -1
- package/build/lib/logging.js +5 -8
- package/build/lib/logging.js.map +1 -1
- package/build/lib/mjpeg.d.ts.map +1 -1
- package/build/lib/mjpeg.js +7 -7
- package/build/lib/mjpeg.js.map +1 -1
- package/build/lib/net.d.ts.map +1 -1
- package/build/lib/net.js +21 -14
- package/build/lib/net.js.map +1 -1
- package/build/lib/node.d.ts.map +1 -1
- package/build/lib/node.js +7 -8
- package/build/lib/node.js.map +1 -1
- package/build/lib/npm.d.ts.map +1 -1
- package/build/lib/npm.js +3 -3
- package/build/lib/npm.js.map +1 -1
- package/build/lib/plist.js +11 -11
- package/build/lib/plist.js.map +1 -1
- package/build/lib/process.d.ts.map +1 -1
- package/build/lib/process.js +2 -2
- package/build/lib/process.js.map +1 -1
- package/build/lib/system.d.ts.map +1 -1
- package/build/lib/system.js +2 -3
- package/build/lib/system.js.map +1 -1
- package/build/lib/tempdir.d.ts +3 -2
- package/build/lib/tempdir.d.ts.map +1 -1
- package/build/lib/tempdir.js +2 -2
- package/build/lib/tempdir.js.map +1 -1
- package/build/lib/timing.d.ts.map +1 -1
- package/build/lib/timing.js +3 -7
- package/build/lib/timing.js.map +1 -1
- package/build/lib/util.d.ts +103 -24
- package/build/lib/util.d.ts.map +1 -1
- package/build/lib/util.js +158 -22
- package/build/lib/util.js.map +1 -1
- package/build/lib/zip.d.ts +42 -42
- package/build/lib/zip.d.ts.map +1 -1
- package/build/lib/zip.js +142 -142
- package/build/lib/zip.js.map +1 -1
- package/lib/console.ts +8 -9
- package/lib/doctor.ts +6 -6
- package/lib/env.ts +5 -5
- package/lib/fs.ts +14 -14
- package/lib/image-util.ts +2 -1
- package/lib/index.ts +7 -1
- package/lib/logging.ts +5 -5
- package/lib/mjpeg.ts +9 -7
- package/lib/net.ts +25 -19
- package/lib/node.ts +7 -8
- package/lib/npm.ts +5 -3
- package/lib/plist.ts +11 -11
- package/lib/process.ts +8 -2
- package/lib/system.ts +2 -3
- package/lib/tempdir.ts +2 -2
- package/lib/timing.ts +3 -5
- package/lib/util.ts +197 -44
- package/lib/zip.ts +223 -221
- package/package.json +11 -12
- package/tsconfig.json +1 -0
package/lib/mjpeg.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import log from './logger';
|
|
3
2
|
import B from 'bluebird';
|
|
4
3
|
import {requireSharp} from './image-util';
|
|
@@ -18,10 +17,11 @@ async function initMJpegConsumer(): Promise<MJpegConsumerConstructor> {
|
|
|
18
17
|
if (!MJpegConsumer) {
|
|
19
18
|
try {
|
|
20
19
|
MJpegConsumer = (await requirePackage('mjpeg-consumer')) as MJpegConsumerConstructor;
|
|
21
|
-
} catch {
|
|
20
|
+
} catch (e) {
|
|
22
21
|
throw new Error(
|
|
23
22
|
'mjpeg-consumer module is required to use MJPEG-over-HTTP features. ' +
|
|
24
|
-
'Please install it first (npm i -g mjpeg-consumer) and restart Appium.'
|
|
23
|
+
'Please install it first (npm i -g mjpeg-consumer) and restart Appium.',
|
|
24
|
+
{cause: e}
|
|
25
25
|
);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
@@ -29,6 +29,7 @@ async function initMJpegConsumer(): Promise<MJpegConsumerConstructor> {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
const MJPEG_SERVER_TIMEOUT_MS = 10000;
|
|
32
|
+
const noop = () => {};
|
|
32
33
|
|
|
33
34
|
/** Class which stores the last bit of data streamed into it */
|
|
34
35
|
export class MJpegStream extends Writable {
|
|
@@ -50,7 +51,7 @@ export class MJpegStream extends Writable {
|
|
|
50
51
|
*/
|
|
51
52
|
constructor(
|
|
52
53
|
mJpegUrl: string,
|
|
53
|
-
errorHandler: (err: Error) => void =
|
|
54
|
+
errorHandler: (err: Error) => void = noop,
|
|
54
55
|
options: WritableOptions = {}
|
|
55
56
|
) {
|
|
56
57
|
super(options);
|
|
@@ -61,7 +62,7 @@ export class MJpegStream extends Writable {
|
|
|
61
62
|
|
|
62
63
|
get lastChunkBase64(): string | null {
|
|
63
64
|
const lastChunk = this.lastChunk;
|
|
64
|
-
if (lastChunk &&
|
|
65
|
+
if (lastChunk && lastChunk.length > 0 && Buffer.isBuffer(lastChunk)) {
|
|
65
66
|
return lastChunk.toString('base64');
|
|
66
67
|
}
|
|
67
68
|
return null;
|
|
@@ -69,7 +70,7 @@ export class MJpegStream extends Writable {
|
|
|
69
70
|
|
|
70
71
|
async lastChunkPNG(): Promise<Buffer | null> {
|
|
71
72
|
const chunk = this.lastChunk;
|
|
72
|
-
if (!chunk ||
|
|
73
|
+
if (!chunk || chunk.length === 0 || !Buffer.isBuffer(chunk)) {
|
|
73
74
|
return null;
|
|
74
75
|
}
|
|
75
76
|
try {
|
|
@@ -118,7 +119,8 @@ export class MJpegStream extends Writable {
|
|
|
118
119
|
message = String(e);
|
|
119
120
|
}
|
|
120
121
|
throw new Error(
|
|
121
|
-
`Cannot connect to the MJPEG stream at ${url}. Original error: ${message}
|
|
122
|
+
`Cannot connect to the MJPEG stream at ${url}. Original error: ${message}`,
|
|
123
|
+
{cause: e}
|
|
122
124
|
);
|
|
123
125
|
}
|
|
124
126
|
|
package/lib/net.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import {fs} from './fs';
|
|
3
|
-
import {toReadableSizeString} from './util';
|
|
2
|
+
import {isPlainObject, toReadableSizeString} from './util';
|
|
4
3
|
import log from './logger';
|
|
5
4
|
import Ftp from 'jsftp';
|
|
6
5
|
import {Timer} from './timing';
|
|
@@ -63,6 +62,8 @@ export interface FtpUploadOptions extends NetOptions {}
|
|
|
63
62
|
/** @deprecated Use {@linkcode FtpUploadOptions} instead. */
|
|
64
63
|
export type NotHttpUploadOptions = FtpUploadOptions;
|
|
65
64
|
|
|
65
|
+
type AuthLike = AuthCredentials | AxiosBasicCredentials;
|
|
66
|
+
|
|
66
67
|
/**
|
|
67
68
|
* Uploads the given file to a remote location. HTTP(S) and FTP protocols are supported.
|
|
68
69
|
*/
|
|
@@ -85,7 +86,7 @@ export async function uploadFile(
|
|
|
85
86
|
if (isHttpUploadOptions(uploadOptions, url)) {
|
|
86
87
|
if (!uploadOptions.fileFieldName) {
|
|
87
88
|
uploadOptions.headers = {
|
|
88
|
-
...(
|
|
89
|
+
...(isPlainObject(uploadOptions.headers) ? uploadOptions.headers : {}),
|
|
89
90
|
'Content-Length': size,
|
|
90
91
|
};
|
|
91
92
|
}
|
|
@@ -107,6 +108,8 @@ export async function uploadFile(
|
|
|
107
108
|
}
|
|
108
109
|
}
|
|
109
110
|
|
|
111
|
+
// #region Private helpers
|
|
112
|
+
|
|
110
113
|
/**
|
|
111
114
|
* Downloads the given file via HTTP(S).
|
|
112
115
|
*
|
|
@@ -128,7 +131,7 @@ export async function downloadFile(
|
|
|
128
131
|
if (axiosAuth) {
|
|
129
132
|
requestOpts.auth = axiosAuth;
|
|
130
133
|
}
|
|
131
|
-
if (
|
|
134
|
+
if (isPlainObject(headers)) {
|
|
132
135
|
requestOpts.headers = headers as RawAxiosRequestConfig['headers'];
|
|
133
136
|
}
|
|
134
137
|
|
|
@@ -150,7 +153,7 @@ export async function downloadFile(
|
|
|
150
153
|
});
|
|
151
154
|
} catch (err) {
|
|
152
155
|
const message = err instanceof Error ? err.message : String(err);
|
|
153
|
-
throw new Error(`Cannot download the file from ${remoteUrl}: ${message}
|
|
156
|
+
throw new Error(`Cannot download the file from ${remoteUrl}: ${message}`, {cause: err});
|
|
154
157
|
}
|
|
155
158
|
|
|
156
159
|
const {size} = await fs.stat(dstPath);
|
|
@@ -174,18 +177,17 @@ export async function downloadFile(
|
|
|
174
177
|
}
|
|
175
178
|
}
|
|
176
179
|
|
|
177
|
-
// #region Private helpers
|
|
178
|
-
|
|
179
|
-
type AuthLike = AuthCredentials | AxiosBasicCredentials;
|
|
180
|
-
|
|
181
180
|
function toAxiosAuth(auth: AuthLike | undefined): AxiosBasicCredentials | null {
|
|
182
|
-
if (!auth || !
|
|
181
|
+
if (!auth || !isPlainObject(auth)) {
|
|
183
182
|
return null;
|
|
184
183
|
}
|
|
185
184
|
|
|
186
185
|
const username = 'username' in auth ? auth.username : auth.user;
|
|
187
186
|
const password = 'password' in auth ? auth.password : auth.pass;
|
|
188
|
-
|
|
187
|
+
if (typeof username !== 'string' || typeof password !== 'string' || !username || !password) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
return {username, password};
|
|
189
191
|
}
|
|
190
192
|
|
|
191
193
|
async function uploadFileToHttp(
|
|
@@ -218,13 +220,13 @@ async function uploadFileToHttp(
|
|
|
218
220
|
const form = new FormData();
|
|
219
221
|
if (formFields) {
|
|
220
222
|
let pairs: [string, unknown][] = [];
|
|
221
|
-
if (
|
|
223
|
+
if (Array.isArray(formFields)) {
|
|
222
224
|
pairs = formFields as [string, unknown][];
|
|
223
|
-
} else if (
|
|
224
|
-
pairs =
|
|
225
|
+
} else if (isPlainObject(formFields)) {
|
|
226
|
+
pairs = Object.entries(formFields);
|
|
225
227
|
}
|
|
226
228
|
for (const [key, value] of pairs) {
|
|
227
|
-
if (
|
|
229
|
+
if (key.toLowerCase() !== fileFieldName?.toLowerCase()) {
|
|
228
230
|
form.append(key, value as string | Buffer);
|
|
229
231
|
}
|
|
230
232
|
}
|
|
@@ -232,19 +234,23 @@ async function uploadFileToHttp(
|
|
|
232
234
|
// AWS S3 POST upload requires this to be the last field; do not move before formFields.
|
|
233
235
|
form.append(fileFieldName, localFileStream);
|
|
234
236
|
requestOpts.headers = {
|
|
235
|
-
...(
|
|
237
|
+
...(isPlainObject(headers) ? headers : {}),
|
|
236
238
|
...form.getHeaders(),
|
|
237
239
|
};
|
|
238
240
|
requestOpts.data = form;
|
|
239
241
|
} else {
|
|
240
|
-
if (
|
|
242
|
+
if (isPlainObject(headers)) {
|
|
241
243
|
requestOpts.headers = headers;
|
|
242
244
|
}
|
|
243
245
|
requestOpts.data = localFileStream;
|
|
244
246
|
}
|
|
245
247
|
log.debug(
|
|
246
248
|
`Performing ${method} to ${href} with options (excluding data): ` +
|
|
247
|
-
JSON.stringify(
|
|
249
|
+
JSON.stringify((() => {
|
|
250
|
+
const requestOptsWithoutData = {...requestOpts} as Record<string, unknown>;
|
|
251
|
+
delete requestOptsWithoutData.data;
|
|
252
|
+
return requestOptsWithoutData;
|
|
253
|
+
})())
|
|
248
254
|
);
|
|
249
255
|
|
|
250
256
|
const {status, statusText} = await axios(requestOpts);
|
|
@@ -261,7 +267,7 @@ async function uploadFileToFtp(
|
|
|
261
267
|
|
|
262
268
|
const ftpOpts: {host: string; port: number; user?: string; pass?: string} = {
|
|
263
269
|
host: hostname ?? '',
|
|
264
|
-
port: port !== undefined && port !== '' ?
|
|
270
|
+
port: port !== undefined && port !== '' ? Number.parseInt(port, 10) : 21,
|
|
265
271
|
};
|
|
266
272
|
if (auth?.user && auth?.pass) {
|
|
267
273
|
ftpOpts.user = auth.user;
|
package/lib/node.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {isWindows} from './system';
|
|
2
2
|
import log from './logger';
|
|
3
|
-
import _ from 'lodash';
|
|
4
3
|
import {exec} from 'teen_process';
|
|
5
4
|
import path from 'node:path';
|
|
6
5
|
import _fs from 'node:fs';
|
|
@@ -156,7 +155,7 @@ async function linkGlobalPackage(packageName: string): Promise<void> {
|
|
|
156
155
|
if (e.stderr) {
|
|
157
156
|
log.debug(e.stderr);
|
|
158
157
|
}
|
|
159
|
-
throw new Error(msg);
|
|
158
|
+
throw new Error(msg, {cause: err});
|
|
160
159
|
}
|
|
161
160
|
}
|
|
162
161
|
|
|
@@ -165,14 +164,14 @@ function extractAllProperties(obj: object): (string | symbol)[] {
|
|
|
165
164
|
for (const prop in obj) {
|
|
166
165
|
stringProperties.push(prop);
|
|
167
166
|
}
|
|
168
|
-
if (
|
|
167
|
+
if (typeof Object.getOwnPropertySymbols === 'function') {
|
|
169
168
|
stringProperties.push(...Object.getOwnPropertySymbols(obj));
|
|
170
169
|
}
|
|
171
170
|
return stringProperties;
|
|
172
171
|
}
|
|
173
172
|
|
|
174
173
|
function _getSizeOfObject(seen: WeakSet<object>, object: object): number {
|
|
175
|
-
if (
|
|
174
|
+
if (object == null) {
|
|
176
175
|
return 0;
|
|
177
176
|
}
|
|
178
177
|
|
|
@@ -181,7 +180,7 @@ function _getSizeOfObject(seen: WeakSet<object>, object: object): number {
|
|
|
181
180
|
const calc = getCalculator(seen);
|
|
182
181
|
for (const key of properties) {
|
|
183
182
|
const val = (object as Record<string | symbol, unknown>)[key];
|
|
184
|
-
if (typeof val === 'object' &&
|
|
183
|
+
if (typeof val === 'object' && val != null) {
|
|
185
184
|
if (seen.has(val as object)) {
|
|
186
185
|
continue;
|
|
187
186
|
}
|
|
@@ -203,7 +202,7 @@ function _getSizeOfObject(seen: WeakSet<object>, object: object): number {
|
|
|
203
202
|
|
|
204
203
|
function getCalculator(seen: WeakSet<object>): SizeCalculator {
|
|
205
204
|
return function calculator(obj: unknown): number {
|
|
206
|
-
if (
|
|
205
|
+
if (Buffer.isBuffer(obj)) {
|
|
207
206
|
return (obj as Buffer).length;
|
|
208
207
|
}
|
|
209
208
|
|
|
@@ -215,11 +214,11 @@ function getCalculator(seen: WeakSet<object>): SizeCalculator {
|
|
|
215
214
|
case 'number':
|
|
216
215
|
return ECMA_SIZES.NUMBER;
|
|
217
216
|
case 'symbol':
|
|
218
|
-
return
|
|
217
|
+
return typeof Symbol.keyFor === 'function' && Symbol.keyFor(obj)
|
|
219
218
|
? (Symbol.keyFor(obj) as string).length * ECMA_SIZES.STRING
|
|
220
219
|
: (obj.toString().length - 8) * ECMA_SIZES.STRING;
|
|
221
220
|
case 'object':
|
|
222
|
-
return
|
|
221
|
+
return Array.isArray(obj)
|
|
223
222
|
? obj.map(getCalculator(seen)).reduce((acc, curr) => acc + curr, 0)
|
|
224
223
|
: _getSizeOfObject(seen, obj as object);
|
|
225
224
|
default:
|
package/lib/npm.ts
CHANGED
|
@@ -104,7 +104,8 @@ export class NPM {
|
|
|
104
104
|
} catch (e) {
|
|
105
105
|
const {stdout = '', stderr = '', code = null} = e as ExecError;
|
|
106
106
|
throw new Error(
|
|
107
|
-
`npm command '${argsCopy.join(' ')}' failed with code ${code}.\n\nSTDOUT:\n${stdout.trim()}\n\nSTDERR:\n${stderr.trim()}
|
|
107
|
+
`npm command '${argsCopy.join(' ')}' failed with code ${code}.\n\nSTDOUT:\n${stdout.trim()}\n\nSTDERR:\n${stderr.trim()}`,
|
|
108
|
+
{cause: e}
|
|
108
109
|
);
|
|
109
110
|
}
|
|
110
111
|
return ret;
|
|
@@ -245,11 +246,12 @@ export class NPM {
|
|
|
245
246
|
const pkgJson = await fs.readFile(pkgJsonPath, 'utf8');
|
|
246
247
|
const pkg = JSON.parse(pkgJson) as PackageJson;
|
|
247
248
|
return {installPath: path.dirname(pkgJsonPath), pkg};
|
|
248
|
-
} catch {
|
|
249
|
+
} catch (e) {
|
|
249
250
|
throw new Error(
|
|
250
251
|
'The package was not downloaded correctly; its package.json ' +
|
|
251
252
|
'did not exist or was unreadable. We looked for it at ' +
|
|
252
|
-
pkgJsonPath
|
|
253
|
+
pkgJsonPath,
|
|
254
|
+
{cause: e}
|
|
253
255
|
);
|
|
254
256
|
}
|
|
255
257
|
}
|
package/lib/plist.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {build as plistBuild, parse as plistParse} from 'plist';
|
|
2
2
|
import bplistCreate from 'bplist-creator';
|
|
3
3
|
import {parseFile, parseBuffer} from 'bplist-parser';
|
|
4
4
|
import {fs} from './fs';
|
|
5
5
|
import log from './logger';
|
|
6
|
-
import
|
|
6
|
+
import {truncateString} from './util';
|
|
7
7
|
|
|
8
8
|
const BPLIST_IDENTIFIER = {
|
|
9
9
|
BUFFER: Buffer.from('bplist00'),
|
|
@@ -37,7 +37,7 @@ export async function parsePlistFile(
|
|
|
37
37
|
return {};
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
let obj: object
|
|
40
|
+
let obj: object;
|
|
41
41
|
let type = 'binary';
|
|
42
42
|
try {
|
|
43
43
|
const parsed = await parseFile(plist);
|
|
@@ -85,8 +85,8 @@ export async function updatePlistFile(
|
|
|
85
85
|
} catch (err) {
|
|
86
86
|
throw log.errorWithException(`Could not update plist: ${(err as Error).message}`);
|
|
87
87
|
}
|
|
88
|
-
|
|
89
|
-
const newPlist = binary ? bplistCreate(obj) :
|
|
88
|
+
Object.assign(obj as Record<string, unknown>, updatedFields);
|
|
89
|
+
const newPlist = binary ? bplistCreate(obj) : plistBuild(obj);
|
|
90
90
|
try {
|
|
91
91
|
await fs.writeFile(plist, newPlist);
|
|
92
92
|
} catch (err) {
|
|
@@ -128,7 +128,7 @@ export function createPlist(object: object, binary = false): Buffer | string {
|
|
|
128
128
|
if (binary) {
|
|
129
129
|
return createBinaryPlist(object);
|
|
130
130
|
}
|
|
131
|
-
return
|
|
131
|
+
return plistBuild(object);
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
/**
|
|
@@ -141,7 +141,7 @@ export function createPlist(object: object, binary = false): Buffer | string {
|
|
|
141
141
|
export function parsePlist(data: string | Buffer): object {
|
|
142
142
|
const textPlist = getXmlPlist(data);
|
|
143
143
|
if (textPlist) {
|
|
144
|
-
return
|
|
144
|
+
return plistParse(textPlist);
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
const binaryPlist = getBinaryPlist(data);
|
|
@@ -150,17 +150,17 @@ export function parsePlist(data: string | Buffer): object {
|
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
throw new Error(
|
|
153
|
-
`Unknown type of plist, data: ${
|
|
153
|
+
`Unknown type of plist, data: ${truncateString(data.toString(), {length: 200})}`
|
|
154
154
|
);
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
async function parseXmlPlistFile(plistFilename: string): Promise<object> {
|
|
158
158
|
const xmlContent = await fs.readFile(plistFilename, 'utf8');
|
|
159
|
-
return
|
|
159
|
+
return plistParse(xmlContent);
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
function getXmlPlist(data: string | Buffer): string | null {
|
|
163
|
-
if (
|
|
163
|
+
if (typeof data === 'string' && data.startsWith(PLIST_IDENTIFIER.TEXT)) {
|
|
164
164
|
return data;
|
|
165
165
|
}
|
|
166
166
|
if (
|
|
@@ -173,7 +173,7 @@ function getXmlPlist(data: string | Buffer): string | null {
|
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
function getBinaryPlist(data: string | Buffer): Buffer | null {
|
|
176
|
-
if (
|
|
176
|
+
if (typeof data === 'string' && data.startsWith(BPLIST_IDENTIFIER.TEXT)) {
|
|
177
177
|
return Buffer.from(data);
|
|
178
178
|
}
|
|
179
179
|
|
package/lib/process.ts
CHANGED
|
@@ -28,7 +28,10 @@ export async function getProcessIds(appName: string): Promise<number[]> {
|
|
|
28
28
|
} catch (err) {
|
|
29
29
|
const code = (err as ExecError).code;
|
|
30
30
|
if (code !== 1) {
|
|
31
|
-
throw new Error(
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Error getting process ids for app '${appName}': ${(err as Error).message}`,
|
|
33
|
+
{cause: err}
|
|
34
|
+
);
|
|
32
35
|
}
|
|
33
36
|
pids = [];
|
|
34
37
|
}
|
|
@@ -56,7 +59,10 @@ export async function killProcess(appName: string, force = false): Promise<void>
|
|
|
56
59
|
} catch (err) {
|
|
57
60
|
const code = (err as ExecError).code;
|
|
58
61
|
if (code !== 1) {
|
|
59
|
-
throw new Error(
|
|
62
|
+
throw new Error(
|
|
63
|
+
`Error killing app '${appName}' with pkill: ${(err as Error).message}`,
|
|
64
|
+
{cause: err}
|
|
65
|
+
);
|
|
60
66
|
}
|
|
61
67
|
}
|
|
62
68
|
}
|
package/lib/system.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {exec} from 'teen_process';
|
|
2
|
-
import _ from 'lodash';
|
|
3
2
|
import os from 'node:os';
|
|
4
3
|
|
|
5
4
|
const VERSION_PATTERN = /^(\d+\.\d+)/m;
|
|
@@ -29,7 +28,7 @@ export function isLinux(): boolean {
|
|
|
29
28
|
* Whether the current Windows process is 64-bit (or WOW64).
|
|
30
29
|
*/
|
|
31
30
|
export function isOSWin64(): boolean {
|
|
32
|
-
return process.arch === 'x64' ||
|
|
31
|
+
return process.arch === 'x64' || Object.hasOwn(process.env, 'PROCESSOR_ARCHITEW6432');
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
/**
|
|
@@ -43,7 +42,7 @@ export async function macOsxVersion(): Promise<string> {
|
|
|
43
42
|
try {
|
|
44
43
|
stdout = (await exec('sw_vers', ['-productVersion'])).stdout.trim();
|
|
45
44
|
} catch (err) {
|
|
46
|
-
throw new Error(`Could not detect Mac OS X Version: ${err}
|
|
45
|
+
throw new Error(`Could not detect Mac OS X Version: ${err}`, {cause: err});
|
|
47
46
|
}
|
|
48
47
|
|
|
49
48
|
const versionMatch = VERSION_PATTERN.exec(stdout);
|
package/lib/tempdir.ts
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import {fs} from './fs';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import nodePath from 'node:path';
|
|
5
|
-
import _ from 'lodash';
|
|
6
5
|
import {constants} from 'node:fs';
|
|
7
6
|
import log from './logger';
|
|
7
|
+
import {memoize} from './util';
|
|
8
8
|
|
|
9
9
|
const RDWR_EXCL = constants.O_CREAT | constants.O_TRUNC | constants.O_RDWR | constants.O_EXCL;
|
|
10
10
|
|
|
@@ -61,7 +61,7 @@ export const openDir = tempDir;
|
|
|
61
61
|
*
|
|
62
62
|
* @returns The same temp directory path on every call.
|
|
63
63
|
*/
|
|
64
|
-
export const staticDir =
|
|
64
|
+
export const staticDir = memoize(async function staticDir (): Promise<string> {
|
|
65
65
|
return tempDir();
|
|
66
66
|
});
|
|
67
67
|
|
package/lib/timing.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
|
-
|
|
3
1
|
const NS_PER_S = 1e9;
|
|
4
2
|
const NS_PER_MS = 1e6;
|
|
5
3
|
|
|
@@ -65,7 +63,7 @@ export class Timer {
|
|
|
65
63
|
* @return {Timer} The current instance, for chaining
|
|
66
64
|
*/
|
|
67
65
|
start(): this {
|
|
68
|
-
if (
|
|
66
|
+
if (this._startTime !== null) {
|
|
69
67
|
throw new Error('Timer has already been started.');
|
|
70
68
|
}
|
|
71
69
|
this._startTime = process.hrtime.bigint();
|
|
@@ -78,12 +76,12 @@ export class Timer {
|
|
|
78
76
|
* @return {Duration} the duration
|
|
79
77
|
*/
|
|
80
78
|
getDuration(): Duration {
|
|
81
|
-
if (
|
|
79
|
+
if (this._startTime === null) {
|
|
82
80
|
throw new Error('Unable to get duration. Timer was not started');
|
|
83
81
|
}
|
|
84
82
|
|
|
85
83
|
let nanoDuration: number;
|
|
86
|
-
if (
|
|
84
|
+
if (Array.isArray(this._startTime)) {
|
|
87
85
|
// startTime was created using process.hrtime()
|
|
88
86
|
const [seconds, nanos] = process.hrtime(this._startTime as [number, number]);
|
|
89
87
|
nanoDuration = seconds * NS_PER_S + nanos;
|