appium 2.0.0-beta.45 → 2.0.0-beta.47
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/README.md +145 -44
- package/build/lib/appium.d.ts +3 -103
- package/build/lib/appium.d.ts.map +1 -1
- package/build/lib/appium.js +679 -549
- package/build/lib/appium.js.map +1 -1
- package/build/lib/cli/args.js +247 -127
- package/build/lib/cli/args.js.map +1 -1
- package/build/lib/cli/driver-command.js +63 -88
- package/build/lib/cli/driver-command.js.map +1 -1
- package/build/lib/cli/extension-command.d.ts +32 -23
- package/build/lib/cli/extension-command.d.ts.map +1 -1
- package/build/lib/cli/extension-command.js +730 -512
- package/build/lib/cli/extension-command.js.map +1 -1
- package/build/lib/cli/extension.d.ts +5 -4
- package/build/lib/cli/extension.d.ts.map +1 -1
- package/build/lib/cli/extension.js +68 -65
- package/build/lib/cli/extension.js.map +1 -1
- package/build/lib/cli/parser.d.ts +3 -3
- package/build/lib/cli/parser.d.ts.map +1 -1
- package/build/lib/cli/parser.js +234 -192
- package/build/lib/cli/parser.js.map +1 -1
- package/build/lib/cli/plugin-command.js +58 -87
- package/build/lib/cli/plugin-command.js.map +1 -1
- package/build/lib/cli/utils.js +66 -69
- package/build/lib/cli/utils.js.map +1 -1
- package/build/lib/config-file.d.ts.map +1 -1
- package/build/lib/config-file.js +189 -120
- package/build/lib/config-file.js.map +1 -1
- package/build/lib/config.d.ts.map +1 -1
- package/build/lib/config.js +254 -213
- package/build/lib/config.js.map +1 -1
- package/build/lib/constants.d.ts +5 -5
- package/build/lib/constants.d.ts.map +1 -1
- package/build/lib/constants.js +64 -59
- package/build/lib/constants.js.map +1 -1
- package/build/lib/extension/driver-config.js +199 -164
- package/build/lib/extension/driver-config.js.map +1 -1
- package/build/lib/extension/extension-config.d.ts +18 -16
- package/build/lib/extension/extension-config.d.ts.map +1 -1
- package/build/lib/extension/extension-config.js +523 -396
- package/build/lib/extension/extension-config.js.map +1 -1
- package/build/lib/extension/index.js +98 -68
- package/build/lib/extension/index.js.map +1 -1
- package/build/lib/extension/manifest-migrations.d.ts +27 -0
- package/build/lib/extension/manifest-migrations.d.ts.map +1 -0
- package/build/lib/extension/manifest-migrations.js +99 -0
- package/build/lib/extension/manifest-migrations.js.map +1 -0
- package/build/lib/extension/manifest.d.ts +7 -56
- package/build/lib/extension/manifest.d.ts.map +1 -1
- package/build/lib/extension/manifest.js +432 -240
- package/build/lib/extension/manifest.js.map +1 -1
- package/build/lib/extension/package-changed.js +57 -61
- package/build/lib/extension/package-changed.js.map +1 -1
- package/build/lib/extension/plugin-config.d.ts +2 -3
- package/build/lib/extension/plugin-config.d.ts.map +1 -1
- package/build/lib/extension/plugin-config.js +94 -70
- package/build/lib/extension/plugin-config.js.map +1 -1
- package/build/lib/grid-register.js +119 -137
- package/build/lib/grid-register.js.map +1 -1
- package/build/lib/logger.d.ts +1 -1
- package/build/lib/logger.d.ts.map +1 -1
- package/build/lib/logger.js +5 -15
- package/build/lib/logger.js.map +1 -1
- package/build/lib/logsink.d.ts.map +1 -1
- package/build/lib/logsink.js +189 -183
- package/build/lib/logsink.js.map +1 -1
- package/build/lib/main.d.ts +19 -12
- package/build/lib/main.d.ts.map +1 -1
- package/build/lib/main.js +330 -304
- package/build/lib/main.js.map +1 -1
- package/build/lib/schema/arg-spec.js +153 -108
- package/build/lib/schema/arg-spec.js.map +1 -1
- package/build/lib/schema/cli-args.js +203 -164
- package/build/lib/schema/cli-args.js.map +1 -1
- package/build/lib/schema/cli-transformers.js +117 -72
- package/build/lib/schema/cli-transformers.js.map +1 -1
- package/build/lib/schema/index.js +17 -32
- package/build/lib/schema/index.js.map +1 -1
- package/build/lib/schema/keywords.js +125 -67
- package/build/lib/schema/keywords.js.map +1 -1
- package/build/lib/schema/schema.d.ts.map +1 -1
- package/build/lib/schema/schema.js +582 -417
- package/build/lib/schema/schema.js.map +1 -1
- package/build/lib/utils.d.ts +41 -255
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +342 -193
- package/build/lib/utils.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/cli.d.ts +45 -34
- package/build/types/cli.d.ts.map +1 -1
- package/build/types/cli.js +3 -0
- package/build/types/cli.js.map +1 -0
- package/build/types/index.d.ts +1 -2
- package/build/types/index.d.ts.map +1 -1
- package/build/types/index.js +19 -0
- package/build/types/index.js.map +1 -0
- package/build/types/manifest/base.d.ts +135 -0
- package/build/types/manifest/base.d.ts.map +1 -0
- package/build/types/manifest/base.js +3 -0
- package/build/types/manifest/base.js.map +1 -0
- package/build/types/manifest/index.d.ts +19 -0
- package/build/types/manifest/index.d.ts.map +1 -0
- package/build/types/manifest/index.js +40 -0
- package/build/types/manifest/index.js.map +1 -0
- package/build/types/manifest/v3.d.ts +139 -0
- package/build/types/manifest/v3.d.ts.map +1 -0
- package/build/types/manifest/v3.js +3 -0
- package/build/types/manifest/v3.js.map +1 -0
- package/lib/appium.js +1 -1
- package/lib/cli/args.js +1 -1
- package/lib/cli/extension-command.js +116 -61
- package/lib/cli/extension.js +9 -8
- package/lib/cli/parser.js +2 -2
- package/lib/config-file.js +2 -3
- package/lib/config.js +3 -2
- package/lib/constants.js +6 -5
- package/lib/extension/extension-config.js +24 -25
- package/lib/extension/manifest-migrations.js +99 -0
- package/lib/extension/manifest.js +79 -72
- package/lib/extension/plugin-config.js +1 -2
- package/lib/logsink.js +26 -5
- package/lib/main.js +58 -50
- package/lib/schema/schema.js +6 -1
- package/lib/utils.js +62 -0
- package/package.json +23 -24
- package/scripts/autoinstall-extensions.js +78 -26
- package/types/cli.ts +81 -42
- package/types/index.ts +1 -2
- package/types/manifest/README.md +30 -0
- package/types/manifest/base.ts +158 -0
- package/types/manifest/index.ts +27 -0
- package/types/manifest/v3.ts +161 -0
- package/build/types/appium-manifest.d.ts +0 -59
- package/build/types/appium-manifest.d.ts.map +0 -1
- package/build/types/extension-manifest.d.ts +0 -55
- package/build/types/extension-manifest.d.ts.map +0 -1
- package/types/appium-manifest.ts +0 -73
- package/types/extension-manifest.ts +0 -64
|
@@ -8,15 +8,11 @@ import {env, fs} from '@appium/support';
|
|
|
8
8
|
import _ from 'lodash';
|
|
9
9
|
import path from 'path';
|
|
10
10
|
import YAML from 'yaml';
|
|
11
|
-
import {DRIVER_TYPE, PLUGIN_TYPE} from '../constants';
|
|
11
|
+
import {CURRENT_SCHEMA_REV, DRIVER_TYPE, PLUGIN_TYPE} from '../constants';
|
|
12
12
|
import log from '../logger';
|
|
13
13
|
import {INSTALL_TYPE_NPM} from './extension-config';
|
|
14
14
|
import {packageDidChange} from './package-changed';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Current configuration schema revision!
|
|
18
|
-
*/
|
|
19
|
-
const CONFIG_SCHEMA_REV = 2;
|
|
15
|
+
import {migrate} from './manifest-migrations';
|
|
20
16
|
|
|
21
17
|
/**
|
|
22
18
|
* The name of the prop (`drivers`) used in `extensions.yaml` for drivers.
|
|
@@ -36,7 +32,7 @@ const CONFIG_DATA_PLUGIN_KEY = `${PLUGIN_TYPE}s`;
|
|
|
36
32
|
const INITIAL_MANIFEST_DATA = Object.freeze({
|
|
37
33
|
[CONFIG_DATA_DRIVER_KEY]: Object.freeze({}),
|
|
38
34
|
[CONFIG_DATA_PLUGIN_KEY]: Object.freeze({}),
|
|
39
|
-
schemaRev:
|
|
35
|
+
schemaRev: CURRENT_SCHEMA_REV,
|
|
40
36
|
});
|
|
41
37
|
|
|
42
38
|
/**
|
|
@@ -93,23 +89,21 @@ export class Manifest {
|
|
|
93
89
|
*
|
|
94
90
|
* Contains proxies for automatic persistence on disk
|
|
95
91
|
* @type {ManifestData}
|
|
96
|
-
* @private
|
|
97
92
|
*/
|
|
98
|
-
|
|
93
|
+
#data;
|
|
99
94
|
|
|
100
95
|
/**
|
|
101
96
|
* Path to `APPIUM_HOME`.
|
|
102
|
-
* @private
|
|
103
97
|
* @type {Readonly<string>}
|
|
104
98
|
*/
|
|
105
|
-
|
|
99
|
+
#appiumHome;
|
|
106
100
|
|
|
107
101
|
/**
|
|
108
102
|
* Path to `extensions.yaml`
|
|
109
103
|
* @type {string}
|
|
110
104
|
* Not set until {@link Manifest.read} is called.
|
|
111
105
|
*/
|
|
112
|
-
|
|
106
|
+
#manifestPath;
|
|
113
107
|
|
|
114
108
|
/**
|
|
115
109
|
* Helps avoid writing multiple times.
|
|
@@ -118,10 +112,9 @@ export class Manifest {
|
|
|
118
112
|
* set to a `Promise`. When the call to `write()` is complete, the `Promise`
|
|
119
113
|
* will resolve and then this value will be set to `undefined`. Concurrent calls
|
|
120
114
|
* made while this value is a `Promise` will return the `Promise` itself.
|
|
121
|
-
* @private
|
|
122
115
|
* @type {Promise<boolean>|undefined}
|
|
123
116
|
*/
|
|
124
|
-
|
|
117
|
+
#writing;
|
|
125
118
|
|
|
126
119
|
/**
|
|
127
120
|
* Helps avoid reading multiple times.
|
|
@@ -130,10 +123,9 @@ export class Manifest {
|
|
|
130
123
|
* set to a `Promise`. When the call to `read()` is complete, the `Promise`
|
|
131
124
|
* will resolve and then this value will be set to `undefined`. Concurrent calls
|
|
132
125
|
* made while this value is a `Promise` will return the `Promise` itself.
|
|
133
|
-
* @private
|
|
134
126
|
* @type {Promise<void>|undefined}
|
|
135
127
|
*/
|
|
136
|
-
|
|
128
|
+
#reading;
|
|
137
129
|
|
|
138
130
|
/**
|
|
139
131
|
* Sets internal data to a fresh clone of {@link INITIAL_MANIFEST_DATA}
|
|
@@ -143,8 +135,8 @@ export class Manifest {
|
|
|
143
135
|
* @private
|
|
144
136
|
*/
|
|
145
137
|
constructor(appiumHome) {
|
|
146
|
-
this
|
|
147
|
-
this
|
|
138
|
+
this.#appiumHome = appiumHome;
|
|
139
|
+
this.#data = _.cloneDeep(INITIAL_MANIFEST_DATA);
|
|
148
140
|
}
|
|
149
141
|
|
|
150
142
|
/**
|
|
@@ -187,14 +179,14 @@ export class Manifest {
|
|
|
187
179
|
*/
|
|
188
180
|
const queue = [
|
|
189
181
|
// look at `package.json` in `APPIUM_HOME` only
|
|
190
|
-
onMatch(path.join(this
|
|
182
|
+
onMatch(path.join(this.#appiumHome, 'package.json')),
|
|
191
183
|
];
|
|
192
184
|
|
|
193
185
|
// add dependencies to the queue
|
|
194
186
|
await new B((resolve, reject) => {
|
|
195
187
|
glob(
|
|
196
188
|
'node_modules/{*,@*/*}/package.json',
|
|
197
|
-
{cwd: this
|
|
189
|
+
{cwd: this.#appiumHome, silent: true, absolute: true},
|
|
198
190
|
// eslint-disable-next-line promise/prefer-await-to-callbacks
|
|
199
191
|
(err) => {
|
|
200
192
|
if (err) {
|
|
@@ -221,7 +213,7 @@ export class Manifest {
|
|
|
221
213
|
* @returns {boolean}
|
|
222
214
|
*/
|
|
223
215
|
hasDriver(name) {
|
|
224
|
-
return Boolean(this.
|
|
216
|
+
return Boolean(this.#data.drivers[name]);
|
|
225
217
|
}
|
|
226
218
|
|
|
227
219
|
/**
|
|
@@ -230,7 +222,7 @@ export class Manifest {
|
|
|
230
222
|
* @returns {boolean}
|
|
231
223
|
*/
|
|
232
224
|
hasPlugin(name) {
|
|
233
|
-
return Boolean(this.
|
|
225
|
+
return Boolean(this.#data.plugins[name]);
|
|
234
226
|
}
|
|
235
227
|
|
|
236
228
|
/**
|
|
@@ -254,6 +246,7 @@ export class Manifest {
|
|
|
254
246
|
appiumVersion: pkgJson.peerDependencies?.appium,
|
|
255
247
|
installType: INSTALL_TYPE_NPM,
|
|
256
248
|
installSpec: `${pkgJson.name}@${pkgJson.version}`,
|
|
249
|
+
installPath: extensionPath,
|
|
257
250
|
};
|
|
258
251
|
|
|
259
252
|
if (isDriver(pkgJson)) {
|
|
@@ -294,22 +287,22 @@ export class Manifest {
|
|
|
294
287
|
*/
|
|
295
288
|
addExtension(extType, extName, extData) {
|
|
296
289
|
const data = _.clone(extData);
|
|
297
|
-
this
|
|
290
|
+
this.#data[`${extType}s`][extName] = data;
|
|
298
291
|
return data;
|
|
299
292
|
}
|
|
300
293
|
|
|
301
294
|
/**
|
|
302
|
-
* Returns the APPIUM_HOME path
|
|
295
|
+
* Returns the `APPIUM_HOME` path
|
|
303
296
|
*/
|
|
304
297
|
get appiumHome() {
|
|
305
|
-
return this
|
|
298
|
+
return this.#appiumHome;
|
|
306
299
|
}
|
|
307
300
|
|
|
308
301
|
/**
|
|
309
|
-
* Returns the path to the manifest file
|
|
302
|
+
* Returns the path to the manifest file (`extensions.yaml`)
|
|
310
303
|
*/
|
|
311
304
|
get manifestPath() {
|
|
312
|
-
return this
|
|
305
|
+
return this.#manifestPath;
|
|
313
306
|
}
|
|
314
307
|
|
|
315
308
|
/**
|
|
@@ -320,7 +313,7 @@ export class Manifest {
|
|
|
320
313
|
* @returns {ExtRecord<ExtType>}
|
|
321
314
|
*/
|
|
322
315
|
getExtensionData(extType) {
|
|
323
|
-
return this
|
|
316
|
+
return this.#data[/** @type {string} */ (`${extType}s`)];
|
|
324
317
|
}
|
|
325
318
|
|
|
326
319
|
/**
|
|
@@ -330,23 +323,23 @@ export class Manifest {
|
|
|
330
323
|
*
|
|
331
324
|
* If `APPIUM_HOME` contains a `package.json` with an `appium` dependency, then a hash of the `package.json` will be taken. If this hash differs from the last hash, the contents of `APPIUM_HOME/node_modules` will be scanned for extensions that may have been installed outside of the `appium` CLI. Any found extensions will be added to the manifest file, and if so, the manifest file will be written to disk.
|
|
332
325
|
*
|
|
333
|
-
* Only one read operation should happen at a time.
|
|
326
|
+
* Only one read operation should happen at a time.
|
|
334
327
|
* @returns {Promise<ManifestData>} The data
|
|
335
328
|
*/
|
|
336
329
|
async read() {
|
|
337
|
-
if (this
|
|
338
|
-
await this
|
|
339
|
-
return this
|
|
330
|
+
if (this.#reading) {
|
|
331
|
+
await this.#reading;
|
|
332
|
+
return this.#data;
|
|
340
333
|
}
|
|
341
334
|
|
|
342
|
-
this
|
|
335
|
+
this.#reading = (async () => {
|
|
343
336
|
/** @type {ManifestData} */
|
|
344
337
|
let data;
|
|
345
338
|
let isNewFile = false;
|
|
346
|
-
await this
|
|
339
|
+
await this.#setManifestPath();
|
|
347
340
|
try {
|
|
348
|
-
log.debug(`Reading ${this
|
|
349
|
-
const yaml = await fs.readFile(this
|
|
341
|
+
log.debug(`Reading ${this.#manifestPath}...`);
|
|
342
|
+
const yaml = await fs.readFile(this.#manifestPath, 'utf8');
|
|
350
343
|
data = YAML.parse(yaml);
|
|
351
344
|
log.debug(`Parsed manifest file: ${JSON.stringify(data, null, 2)}`);
|
|
352
345
|
} catch (err) {
|
|
@@ -354,10 +347,12 @@ export class Manifest {
|
|
|
354
347
|
data = _.cloneDeep(INITIAL_MANIFEST_DATA);
|
|
355
348
|
isNewFile = true;
|
|
356
349
|
} else {
|
|
357
|
-
if (this
|
|
350
|
+
if (this.#manifestPath) {
|
|
358
351
|
throw new Error(
|
|
359
352
|
`Appium had trouble loading the extension installation ` +
|
|
360
|
-
`cache file (${this
|
|
353
|
+
`cache file (${this.#manifestPath}). It may be invalid YAML. Specific error: ${
|
|
354
|
+
err.message
|
|
355
|
+
}`
|
|
361
356
|
);
|
|
362
357
|
} else {
|
|
363
358
|
throw new Error(
|
|
@@ -367,47 +362,58 @@ export class Manifest {
|
|
|
367
362
|
}
|
|
368
363
|
}
|
|
369
364
|
|
|
370
|
-
this
|
|
371
|
-
|
|
365
|
+
this.#data = data;
|
|
366
|
+
|
|
367
|
+
let shouldWrite = false;
|
|
368
|
+
|
|
369
|
+
if ((data.schemaRev ?? 0) < CURRENT_SCHEMA_REV) {
|
|
370
|
+
log.debug(
|
|
371
|
+
`Updating manifest schema from rev ${data.schemaRev ?? '(none)'} to ${CURRENT_SCHEMA_REV}`
|
|
372
|
+
);
|
|
373
|
+
shouldWrite = await migrate(this, this.#data);
|
|
374
|
+
}
|
|
375
|
+
|
|
372
376
|
if (
|
|
373
|
-
|
|
374
|
-
(await
|
|
377
|
+
shouldWrite ||
|
|
378
|
+
((await env.hasAppiumDependency(this.appiumHome)) &&
|
|
379
|
+
(await packageDidChange(this.appiumHome)))
|
|
375
380
|
) {
|
|
376
|
-
|
|
381
|
+
shouldWrite = await this.syncWithInstalledExtensions();
|
|
377
382
|
}
|
|
378
383
|
|
|
379
|
-
if (isNewFile ||
|
|
384
|
+
if (isNewFile || shouldWrite) {
|
|
380
385
|
await this.write();
|
|
381
386
|
}
|
|
382
387
|
})();
|
|
383
388
|
try {
|
|
384
|
-
await this
|
|
385
|
-
return this
|
|
389
|
+
await this.#reading;
|
|
390
|
+
return this.#data;
|
|
386
391
|
} finally {
|
|
387
|
-
this
|
|
392
|
+
this.#reading = undefined;
|
|
388
393
|
}
|
|
389
394
|
}
|
|
390
395
|
|
|
391
396
|
/**
|
|
392
|
-
* Ensures
|
|
397
|
+
* Ensures the internal manifest path is set.
|
|
393
398
|
*
|
|
394
399
|
* Creates the directory if necessary.
|
|
395
|
-
* @private
|
|
396
400
|
* @returns {Promise<string>}
|
|
397
401
|
*/
|
|
398
|
-
async
|
|
399
|
-
if (!this
|
|
400
|
-
this
|
|
402
|
+
async #setManifestPath() {
|
|
403
|
+
if (!this.#manifestPath) {
|
|
404
|
+
this.#manifestPath = await env.resolveManifestPath(this.#appiumHome);
|
|
401
405
|
|
|
402
406
|
/* istanbul ignore if */
|
|
403
|
-
if (path.relative(this
|
|
407
|
+
if (path.relative(this.#appiumHome, this.#manifestPath).startsWith('.')) {
|
|
404
408
|
throw new Error(
|
|
405
|
-
`Mismatch between location of APPIUM_HOME and manifest file. APPIUM_HOME: ${
|
|
409
|
+
`Mismatch between location of APPIUM_HOME and manifest file. APPIUM_HOME: ${
|
|
410
|
+
this.appiumHome
|
|
411
|
+
}, manifest file: ${this.#manifestPath}`
|
|
406
412
|
);
|
|
407
413
|
}
|
|
408
414
|
}
|
|
409
415
|
|
|
410
|
-
return this
|
|
416
|
+
return this.#manifestPath;
|
|
411
417
|
}
|
|
412
418
|
|
|
413
419
|
/**
|
|
@@ -419,34 +425,35 @@ export class Manifest {
|
|
|
419
425
|
* @returns {Promise<boolean>} Whether the data was written
|
|
420
426
|
*/
|
|
421
427
|
async write() {
|
|
422
|
-
if (this
|
|
423
|
-
return this
|
|
428
|
+
if (this.#writing) {
|
|
429
|
+
return this.#writing;
|
|
424
430
|
}
|
|
425
|
-
this
|
|
426
|
-
await this
|
|
431
|
+
this.#writing = (async () => {
|
|
432
|
+
await this.#setManifestPath();
|
|
427
433
|
try {
|
|
428
|
-
await fs.mkdirp(path.dirname(this
|
|
434
|
+
await fs.mkdirp(path.dirname(this.#manifestPath));
|
|
429
435
|
} catch (err) {
|
|
430
436
|
throw new Error(
|
|
431
437
|
`Appium could not create the directory for the manifest file: ${path.dirname(
|
|
432
|
-
this
|
|
438
|
+
this.#manifestPath
|
|
433
439
|
)}. Original error: ${err.message}`
|
|
434
440
|
);
|
|
435
441
|
}
|
|
436
442
|
try {
|
|
437
|
-
await fs.writeFile(this
|
|
443
|
+
await fs.writeFile(this.#manifestPath, YAML.stringify(this.#data), 'utf8');
|
|
438
444
|
return true;
|
|
439
445
|
} catch (err) {
|
|
440
446
|
throw new Error(
|
|
441
|
-
`Appium could not write to manifest at ${this
|
|
442
|
-
|
|
447
|
+
`Appium could not write to manifest at ${this.#manifestPath} using APPIUM_HOME ${
|
|
448
|
+
this.#appiumHome
|
|
449
|
+
}. Please ensure it is writable. Original error: ${err.message}`
|
|
443
450
|
);
|
|
444
451
|
}
|
|
445
452
|
})();
|
|
446
453
|
try {
|
|
447
|
-
return await this
|
|
454
|
+
return await this.#writing;
|
|
448
455
|
} finally {
|
|
449
|
-
this
|
|
456
|
+
this.#writing = undefined;
|
|
450
457
|
}
|
|
451
458
|
}
|
|
452
459
|
}
|
|
@@ -472,18 +479,18 @@ export class Manifest {
|
|
|
472
479
|
*/
|
|
473
480
|
|
|
474
481
|
/**
|
|
475
|
-
* @template
|
|
476
|
-
* @typedef {import('appium/types').ExtPackageJson<
|
|
482
|
+
* @template {ExtensionType} ExtType
|
|
483
|
+
* @typedef {import('appium/types').ExtPackageJson<ExtType>} ExtPackageJson
|
|
477
484
|
*/
|
|
478
485
|
|
|
479
486
|
/**
|
|
480
|
-
* @template
|
|
481
|
-
* @typedef {import('appium/types').ExtManifest<
|
|
487
|
+
* @template {ExtensionType} ExtType
|
|
488
|
+
* @typedef {import('appium/types').ExtManifest<ExtType>} ExtManifest
|
|
482
489
|
*/
|
|
483
490
|
|
|
484
491
|
/**
|
|
485
|
-
* @template
|
|
486
|
-
* @typedef {import('appium/types').ExtRecord<
|
|
492
|
+
* @template {ExtensionType} ExtType
|
|
493
|
+
* @typedef {import('appium/types').ExtRecord<ExtType>} ExtRecord
|
|
487
494
|
*/
|
|
488
495
|
|
|
489
496
|
/**
|
|
@@ -72,7 +72,7 @@ export class PluginConfig extends ExtensionConfig {
|
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
74
|
*
|
|
75
|
-
* @param {(keyof
|
|
75
|
+
* @param {(keyof import('appium/types').ExtRecord<PluginType>)[]} activeNames
|
|
76
76
|
* @returns {void}
|
|
77
77
|
*/
|
|
78
78
|
print(activeNames) {
|
|
@@ -106,7 +106,6 @@ export class PluginConfig extends ExtensionConfig {
|
|
|
106
106
|
*/
|
|
107
107
|
|
|
108
108
|
/**
|
|
109
|
-
* @typedef {import('appium/types').PluginRecord} PluginRecord
|
|
110
109
|
* @typedef {import('@appium/types').PluginType} PluginType
|
|
111
110
|
* @typedef {import('appium/types').ExtMetadata<PluginType>} PluginMetadata
|
|
112
111
|
* @typedef {import('./manifest').Manifest} Manifest
|
package/lib/logsink.js
CHANGED
|
@@ -33,6 +33,8 @@ const npmToWinstonLevels = {
|
|
|
33
33
|
error: 'error',
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
+
const encounteredPrefixes = [];
|
|
37
|
+
|
|
36
38
|
let log = null;
|
|
37
39
|
let useLocalTimeZone = false;
|
|
38
40
|
|
|
@@ -186,8 +188,21 @@ async function createTransports(args) {
|
|
|
186
188
|
return transports;
|
|
187
189
|
}
|
|
188
190
|
|
|
191
|
+
function getColorizedPrefix(prefix) {
|
|
192
|
+
let prefixId = prefix.split('@')[0].trim();
|
|
193
|
+
prefixId = prefixId.split(' (')[0].trim();
|
|
194
|
+
if (encounteredPrefixes.indexOf(prefixId) < 0) {
|
|
195
|
+
encounteredPrefixes.push(prefixId);
|
|
196
|
+
}
|
|
197
|
+
// using a multiple of 16 should cause 16 colors to be created
|
|
198
|
+
const colorNumber = encounteredPrefixes.indexOf(prefixId) * 16;
|
|
199
|
+
// use the modulus to cycle around color wheel
|
|
200
|
+
return `\x1b[38;5;${colorNumber % 256}m${prefix}\x1b[0m`;
|
|
201
|
+
}
|
|
202
|
+
|
|
189
203
|
async function init(args) {
|
|
190
204
|
npmlog.level = 'silent';
|
|
205
|
+
|
|
191
206
|
// set de facto param passed to timestamp function
|
|
192
207
|
useLocalTimeZone = args.localTimezone;
|
|
193
208
|
|
|
@@ -205,11 +220,17 @@ async function init(args) {
|
|
|
205
220
|
let msg = logObj.message;
|
|
206
221
|
if (logObj.prefix) {
|
|
207
222
|
const prefix = `[${logObj.prefix}]`;
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
223
|
+
if (args.logNoColors) {
|
|
224
|
+
msg = `${prefix} ${msg}`;
|
|
225
|
+
} if (prefix === '[Appium]') {
|
|
226
|
+
msg = `${prefix.magenta} ${msg}`;
|
|
227
|
+
} else {
|
|
228
|
+
msg = `${getColorizedPrefix(prefix)} ${msg}`;
|
|
229
|
+
}
|
|
230
|
+
log[winstonLevel](msg);
|
|
231
|
+
if (args.logHandler && _.isFunction(args.logHandler)) {
|
|
232
|
+
args.logHandler(logObj.level, msg);
|
|
233
|
+
}
|
|
213
234
|
}
|
|
214
235
|
});
|
|
215
236
|
}
|
package/lib/main.js
CHANGED
|
@@ -23,10 +23,17 @@ import {
|
|
|
23
23
|
} from './config';
|
|
24
24
|
import {readConfigFile} from './config-file';
|
|
25
25
|
import {loadExtensions, getActivePlugins, getActiveDrivers} from './extension';
|
|
26
|
-
import {
|
|
26
|
+
import {SERVER_SUBCOMMAND} from './constants';
|
|
27
27
|
import registerNode from './grid-register';
|
|
28
28
|
import {getDefaultsForSchema, validate} from './schema/schema';
|
|
29
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
inspect,
|
|
31
|
+
adjustNodePath,
|
|
32
|
+
isDriverCommandArgs,
|
|
33
|
+
isExtensionCommandArgs,
|
|
34
|
+
isPluginCommandArgs,
|
|
35
|
+
isServerCommandArgs,
|
|
36
|
+
} from './utils';
|
|
30
37
|
|
|
31
38
|
const {resolveAppiumHome} = env;
|
|
32
39
|
|
|
@@ -143,16 +150,6 @@ function getExtraMethodMap(driverClasses, pluginClasses) {
|
|
|
143
150
|
{}
|
|
144
151
|
);
|
|
145
152
|
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* @template [T=WithServerSubcommand]
|
|
149
|
-
* @param {Args<T>} args
|
|
150
|
-
* @returns {args is Args<WithServerSubcommand>}
|
|
151
|
-
*/
|
|
152
|
-
function areServerCommandArgs(args) {
|
|
153
|
-
return args.subcommand === SERVER_SUBCOMMAND;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
153
|
/**
|
|
157
154
|
* Initializes Appium, but does not start the server.
|
|
158
155
|
*
|
|
@@ -160,9 +157,10 @@ function areServerCommandArgs(args) {
|
|
|
160
157
|
*
|
|
161
158
|
* If `args` contains a non-empty `subcommand` which is not `server`, this function will return an empty object.
|
|
162
159
|
*
|
|
163
|
-
* @template [
|
|
164
|
-
* @
|
|
165
|
-
* @
|
|
160
|
+
* @template {CliCommand} [Cmd=ServerCommand]
|
|
161
|
+
* @template {CliExtensionSubcommand|void} [SubCmd=void]
|
|
162
|
+
* @param {Args<Cmd, SubCmd>} [args] - Partial args (progammatic usage only)
|
|
163
|
+
* @returns {Promise<InitResult<Cmd>>}
|
|
166
164
|
* @example
|
|
167
165
|
* import {init, getSchema} from 'appium';
|
|
168
166
|
* const options = {}; // config object
|
|
@@ -178,7 +176,7 @@ async function init(args) {
|
|
|
178
176
|
|
|
179
177
|
const parser = getParser();
|
|
180
178
|
let throwInsteadOfExit = false;
|
|
181
|
-
/** @type {Args<
|
|
179
|
+
/** @type {Args<Cmd, SubCmd>} */
|
|
182
180
|
let preConfigArgs;
|
|
183
181
|
|
|
184
182
|
if (args) {
|
|
@@ -193,7 +191,7 @@ async function init(args) {
|
|
|
193
191
|
preConfigArgs = {...args, subcommand: args.subcommand ?? SERVER_SUBCOMMAND};
|
|
194
192
|
} else {
|
|
195
193
|
// otherwise parse from CLI
|
|
196
|
-
preConfigArgs = /** @type {Args<
|
|
194
|
+
preConfigArgs = /** @type {Args<Cmd, SubCmd>} */ (parser.parseArgs());
|
|
197
195
|
}
|
|
198
196
|
|
|
199
197
|
const configResult = await readConfigFile(preConfigArgs.configFile);
|
|
@@ -211,15 +209,15 @@ async function init(args) {
|
|
|
211
209
|
// 1. command line args
|
|
212
210
|
// 2. config file
|
|
213
211
|
// 3. defaults from config file.
|
|
214
|
-
if (
|
|
212
|
+
if (isServerCommandArgs(preConfigArgs)) {
|
|
215
213
|
const defaults = getDefaultsForSchema(false);
|
|
216
214
|
|
|
217
215
|
/** @type {ParsedArgs} */
|
|
218
|
-
const serverArgs = _.defaultsDeep(preConfigArgs, configResult.config?.server, defaults);
|
|
216
|
+
const serverArgs = _.defaultsDeep({}, preConfigArgs, configResult.config?.server, defaults);
|
|
219
217
|
|
|
220
218
|
if (preConfigArgs.showConfig) {
|
|
221
219
|
showConfig(getNonDefaultServerArgs(preConfigArgs), configResult, defaults, serverArgs);
|
|
222
|
-
return {};
|
|
220
|
+
return /** @type {InitResult<Cmd>} */ ({});
|
|
223
221
|
}
|
|
224
222
|
|
|
225
223
|
await logsinkInit(serverArgs);
|
|
@@ -252,49 +250,49 @@ async function init(args) {
|
|
|
252
250
|
appiumDriver.driverConfig = driverConfig;
|
|
253
251
|
await preflightChecks(serverArgs, throwInsteadOfExit);
|
|
254
252
|
|
|
255
|
-
return /** @type {
|
|
253
|
+
return /** @type {InitResult<Cmd>} */ ({
|
|
256
254
|
appiumDriver,
|
|
257
255
|
parsedArgs: serverArgs,
|
|
258
256
|
driverConfig,
|
|
259
257
|
pluginConfig,
|
|
260
258
|
});
|
|
261
259
|
} else {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (preConfigArgs.subcommand === PLUGIN_TYPE) {
|
|
272
|
-
await runExtensionCommand(extensionCommandArgs, pluginConfig);
|
|
273
|
-
return {};
|
|
260
|
+
if (isExtensionCommandArgs(preConfigArgs)) {
|
|
261
|
+
// if the user has requested the 'driver' CLI, don't run the normal server,
|
|
262
|
+
// but instead pass control to the driver CLI
|
|
263
|
+
if (isDriverCommandArgs(preConfigArgs)) {
|
|
264
|
+
await runExtensionCommand(preConfigArgs, driverConfig);
|
|
265
|
+
}
|
|
266
|
+
if (isPluginCommandArgs(preConfigArgs)) {
|
|
267
|
+
await runExtensionCommand(preConfigArgs, pluginConfig);
|
|
268
|
+
}
|
|
274
269
|
}
|
|
275
|
-
|
|
276
|
-
return {}; // should never happen
|
|
270
|
+
return /** @type {InitResult<Cmd>} */ ({});
|
|
277
271
|
}
|
|
278
272
|
}
|
|
279
273
|
|
|
280
274
|
/**
|
|
281
275
|
* Initializes Appium's config. Starts server if appropriate and resolves the
|
|
282
276
|
* server instance if so; otherwise resolves w/ `undefined`.
|
|
283
|
-
* @template [
|
|
284
|
-
* @
|
|
285
|
-
* @
|
|
277
|
+
* @template {CliCommand} [Cmd=ServerCommand]
|
|
278
|
+
* @template {CliExtensionSubcommand|void} [SubCmd=void]
|
|
279
|
+
* @param {Args<Cmd, SubCmd>} [args] - Arguments from CLI or otherwise
|
|
280
|
+
* @returns {Promise<Cmd extends ServerCommand ? import('@appium/types').AppiumServer : void>}
|
|
286
281
|
*/
|
|
287
282
|
async function main(args) {
|
|
288
|
-
const
|
|
289
|
-
await init(args)
|
|
290
|
-
);
|
|
283
|
+
const initResult = await init(args);
|
|
291
284
|
|
|
292
|
-
if (
|
|
285
|
+
if (_.isEmpty(initResult)) {
|
|
293
286
|
// if this branch is taken, we've run a different subcommand, so there's nothing
|
|
294
287
|
// left to do here.
|
|
295
|
-
return
|
|
288
|
+
return /** @type {Cmd extends ServerCommand ? import('@appium/types').AppiumServer : void} */ (
|
|
289
|
+
undefined
|
|
290
|
+
);
|
|
296
291
|
}
|
|
297
292
|
|
|
293
|
+
const {appiumDriver, pluginConfig, driverConfig, parsedArgs} =
|
|
294
|
+
/** @type {InitResult<ServerCommand>} */ (initResult);
|
|
295
|
+
|
|
298
296
|
const pluginClasses = getActivePlugins(pluginConfig, parsedArgs.usePlugins);
|
|
299
297
|
// set the active plugins on the umbrella driver so it can use them for commands
|
|
300
298
|
appiumDriver.pluginClasses = pluginClasses;
|
|
@@ -377,7 +375,9 @@ async function main(args) {
|
|
|
377
375
|
driverConfig.print();
|
|
378
376
|
pluginConfig.print([...pluginClasses.values()]);
|
|
379
377
|
|
|
380
|
-
return
|
|
378
|
+
return /** @type {Cmd extends ServerCommand ? import('@appium/types').AppiumServer : void} */ (
|
|
379
|
+
server
|
|
380
|
+
);
|
|
381
381
|
}
|
|
382
382
|
|
|
383
383
|
// NOTE: this is here for backwards compat for any scripts referencing `main.js` directly
|
|
@@ -397,7 +397,12 @@ export {main, init, resolveAppiumHome};
|
|
|
397
397
|
* @typedef {import('@appium/types').PluginType} PluginType
|
|
398
398
|
* @typedef {import('@appium/types').DriverClass} DriverClass
|
|
399
399
|
* @typedef {import('@appium/types').PluginClass} PluginClass
|
|
400
|
-
* @typedef {import('appium/types').
|
|
400
|
+
* @typedef {import('appium/types').CliCommand} CliCommand
|
|
401
|
+
* @typedef {import('appium/types').CliExtensionSubcommand} CliExtensionSubcommand
|
|
402
|
+
* @typedef {import('appium/types').CliExtensionCommand} CliExtensionCommand
|
|
403
|
+
* @typedef {import('appium/types').ServerCommand} ServerCommand
|
|
404
|
+
* @typedef {import('appium/types').DriverCommand} DriverCommand
|
|
405
|
+
* @typedef {import('appium/types').PluginCommand} PluginCommand
|
|
401
406
|
* @typedef {import('./extension').DriverNameMap} DriverNameMap
|
|
402
407
|
* @typedef {import('./extension').PluginNameMap} PluginNameMap
|
|
403
408
|
*/
|
|
@@ -414,15 +419,18 @@ export {main, init, resolveAppiumHome};
|
|
|
414
419
|
*/
|
|
415
420
|
|
|
416
421
|
/**
|
|
417
|
-
* @
|
|
422
|
+
* @template {CliCommand} Cmd
|
|
423
|
+
* @typedef {Cmd extends ServerCommand ? ServerInitData & import('./extension').ExtensionConfigs : ExtCommandInitResult} InitResult
|
|
418
424
|
*/
|
|
419
425
|
|
|
420
426
|
/**
|
|
421
|
-
* @template [
|
|
422
|
-
* @
|
|
427
|
+
* @template {CliCommand} [Cmd=ServerCommand]
|
|
428
|
+
* @template {CliExtensionSubcommand|void} [SubCmd=void]
|
|
429
|
+
* @typedef {import('appium/types').Args<Cmd, SubCmd>} Args
|
|
423
430
|
*/
|
|
424
431
|
|
|
425
432
|
/**
|
|
426
|
-
* @template [
|
|
427
|
-
* @
|
|
433
|
+
* @template {CliCommand} [Cmd=ServerCommand]
|
|
434
|
+
* @template {CliExtensionSubcommand|void} [SubCmd=void]
|
|
435
|
+
* @typedef {import('appium/types').ParsedArgs<Cmd, SubCmd>} ParsedArgs
|
|
428
436
|
*/
|
package/lib/schema/schema.js
CHANGED
|
@@ -43,6 +43,8 @@ export class RoachHotelMap extends Map {
|
|
|
43
43
|
*/
|
|
44
44
|
export const ALLOWED_SCHEMA_EXTENSIONS = new Set(['.json', '.js', '.cjs']);
|
|
45
45
|
|
|
46
|
+
const SCHEMA_KEY = '$schema';
|
|
47
|
+
|
|
46
48
|
/**
|
|
47
49
|
* A wrapper around Ajv and schema-related functions.
|
|
48
50
|
*
|
|
@@ -316,7 +318,7 @@ class AppiumSchema {
|
|
|
316
318
|
}
|
|
317
319
|
const normalizedExtName = _.kebabCase(extName);
|
|
318
320
|
if (this.hasRegisteredSchema(extType, normalizedExtName)) {
|
|
319
|
-
if (this._registeredSchemas[extType].get(normalizedExtName)
|
|
321
|
+
if (_.isEqual(this._registeredSchemas[extType].get(normalizedExtName), schema)) {
|
|
320
322
|
return;
|
|
321
323
|
}
|
|
322
324
|
throw new SchemaNameConflictError(extType, extName);
|
|
@@ -441,6 +443,9 @@ class AppiumSchema {
|
|
|
441
443
|
for (const {properties, prefix} of stack) {
|
|
442
444
|
const pairs = _.toPairs(properties);
|
|
443
445
|
for (const [key, value] of pairs) {
|
|
446
|
+
if (key === SCHEMA_KEY) {
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
444
449
|
const {properties, $ref} = value;
|
|
445
450
|
if (properties) {
|
|
446
451
|
stack.push({
|