appium 2.2.3 → 2.4.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/README.md +131 -158
- package/build/lib/appium.d.ts +76 -4
- package/build/lib/appium.d.ts.map +1 -1
- package/build/lib/appium.js +327 -1
- package/build/lib/appium.js.map +1 -1
- package/build/lib/cli/args.d.ts.map +1 -1
- package/build/lib/cli/args.js +24 -2
- package/build/lib/cli/args.js.map +1 -1
- package/build/lib/cli/driver-command.d.ts +16 -0
- package/build/lib/cli/driver-command.d.ts.map +1 -1
- package/build/lib/cli/driver-command.js +16 -0
- package/build/lib/cli/driver-command.js.map +1 -1
- package/build/lib/cli/extension-command.d.ts +26 -2
- package/build/lib/cli/extension-command.d.ts.map +1 -1
- package/build/lib/cli/extension-command.js +135 -4
- package/build/lib/cli/extension-command.js.map +1 -1
- package/build/lib/cli/parser.d.ts.map +1 -1
- package/build/lib/cli/parser.js +11 -7
- package/build/lib/cli/parser.js.map +1 -1
- package/build/lib/cli/plugin-command.d.ts +16 -0
- package/build/lib/cli/plugin-command.d.ts.map +1 -1
- package/build/lib/cli/plugin-command.js +16 -0
- package/build/lib/cli/plugin-command.js.map +1 -1
- package/build/lib/cli/utils.d.ts.map +1 -1
- package/build/lib/cli/utils.js +3 -4
- package/build/lib/cli/utils.js.map +1 -1
- package/build/lib/config-file.d.ts +1 -1
- package/build/lib/config.d.ts +8 -7
- package/build/lib/config.d.ts.map +1 -1
- package/build/lib/config.js +54 -64
- package/build/lib/config.js.map +1 -1
- package/build/lib/constants.d.ts +10 -0
- package/build/lib/constants.d.ts.map +1 -1
- package/build/lib/constants.js +11 -1
- package/build/lib/constants.js.map +1 -1
- package/build/lib/doctor/doctor.d.ts +55 -0
- package/build/lib/doctor/doctor.d.ts.map +1 -0
- package/build/lib/doctor/doctor.js +201 -0
- package/build/lib/doctor/doctor.js.map +1 -0
- package/build/lib/extension/driver-config.d.ts +2 -2
- package/build/lib/extension/driver-config.d.ts.map +1 -1
- package/build/lib/extension/driver-config.js +4 -4
- package/build/lib/extension/driver-config.js.map +1 -1
- package/build/lib/extension/extension-config.d.ts +10 -3
- package/build/lib/extension/extension-config.d.ts.map +1 -1
- package/build/lib/extension/extension-config.js +32 -14
- package/build/lib/extension/extension-config.js.map +1 -1
- package/build/lib/extension/index.d.ts +6 -4
- package/build/lib/extension/index.d.ts.map +1 -1
- package/build/lib/extension/index.js +74 -32
- package/build/lib/extension/index.js.map +1 -1
- package/build/lib/extension/manifest.js +1 -1
- package/build/lib/extension/manifest.js.map +1 -1
- package/build/lib/extension/plugin-config.js +1 -1
- package/build/lib/extension/plugin-config.js.map +1 -1
- package/build/lib/grid-register.d.ts.map +1 -1
- package/build/lib/grid-register.js +1 -2
- package/build/lib/grid-register.js.map +1 -1
- package/build/lib/main.d.ts +4 -0
- package/build/lib/main.d.ts.map +1 -1
- package/build/lib/main.js +31 -52
- package/build/lib/main.js.map +1 -1
- package/build/lib/schema/schema.d.ts +5 -0
- package/build/lib/schema/schema.d.ts.map +1 -1
- package/build/lib/schema/schema.js +7 -7
- package/build/lib/schema/schema.js.map +1 -1
- package/build/lib/utils.d.ts +3 -0
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +2 -1
- package/build/lib/utils.js.map +1 -1
- package/build/types/cli.d.ts +1 -1
- package/build/types/cli.d.ts.map +1 -1
- package/lib/appium.js +388 -2
- package/lib/cli/args.js +27 -2
- package/lib/cli/driver-command.js +18 -0
- package/lib/cli/extension-command.js +160 -9
- package/lib/cli/parser.js +22 -8
- package/lib/cli/plugin-command.js +18 -0
- package/lib/cli/utils.js +5 -7
- package/lib/config.js +46 -65
- package/lib/constants.js +12 -0
- package/lib/doctor/doctor.js +209 -0
- package/lib/extension/driver-config.js +3 -3
- package/lib/extension/extension-config.js +33 -15
- package/lib/extension/index.js +80 -43
- package/lib/grid-register.js +1 -2
- package/lib/main.js +42 -61
- package/lib/utils.js +2 -1
- package/package.json +15 -18
- package/types/cli.ts +1 -1
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import '@colors/colors';
|
|
2
|
+
import _ from 'lodash';
|
|
3
|
+
import { util, doctor, logger } from '@appium/support';
|
|
4
|
+
|
|
5
|
+
export class Doctor {
|
|
6
|
+
/**
|
|
7
|
+
* @param {DoctorCheck[]} [checks=[]]
|
|
8
|
+
*/
|
|
9
|
+
constructor(checks = []) {
|
|
10
|
+
this.log = logger.getLogger('Doctor');
|
|
11
|
+
/** @type {DoctorCheck[]} */
|
|
12
|
+
this.checks = checks;
|
|
13
|
+
this.checks
|
|
14
|
+
.filter((c) => _.isNil(c.log))
|
|
15
|
+
.forEach((c) => { c.log = this.log; });
|
|
16
|
+
/** @type {DoctorIssue[]} */
|
|
17
|
+
this.foundIssues = [];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @returns {DoctorIssue[]}
|
|
22
|
+
*/
|
|
23
|
+
get issuesRequiredToFix() {
|
|
24
|
+
return this.foundIssues.filter((f) => !f.check.isOptional());
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @returns {DoctorIssue[]}
|
|
29
|
+
*/
|
|
30
|
+
get issuesOptionalToFix() {
|
|
31
|
+
return this.foundIssues.filter((f) => f.check.isOptional());
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The doctor shows the report
|
|
36
|
+
*/
|
|
37
|
+
async diagnose() {
|
|
38
|
+
this.log.info(`### Starting doctor diagnostics ###`);
|
|
39
|
+
this.foundIssues = [];
|
|
40
|
+
for (const check of this.checks) {
|
|
41
|
+
const res = await check.diagnose();
|
|
42
|
+
const issue = this.toIssue(res, check);
|
|
43
|
+
if (issue) {
|
|
44
|
+
this.foundIssues.push(issue);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
this.log.info(
|
|
48
|
+
`### Diagnostic completed, ${this.buildFixMessage()}. ###`
|
|
49
|
+
);
|
|
50
|
+
this.log.info('');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @returns {Promise<boolean>}
|
|
55
|
+
*/
|
|
56
|
+
async reportManualIssues() {
|
|
57
|
+
const manualIssues = _.filter(this.issuesRequiredToFix, (f) => !f.check.hasAutofix());
|
|
58
|
+
const manualIssuesOptional = _.filter(this.issuesOptionalToFix, (f) => !f.check.hasAutofix());
|
|
59
|
+
|
|
60
|
+
const handleIssues = async (headerLogs, issues) => {
|
|
61
|
+
if (_.isEmpty(issues)) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
for (const logMsg of headerLogs) {
|
|
66
|
+
this.log.info(logMsg);
|
|
67
|
+
}
|
|
68
|
+
/** @type {string[]} */
|
|
69
|
+
const fixMessages = [];
|
|
70
|
+
for (const issue of issues) {
|
|
71
|
+
const message = await issue.check.fix();
|
|
72
|
+
if (message) {
|
|
73
|
+
fixMessages.push(message);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
for (const m of _.uniq(fixMessages)) {
|
|
77
|
+
this.log.warn(` \u279C ${m}`);
|
|
78
|
+
}
|
|
79
|
+
this.log.info('');
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
await handleIssues([
|
|
83
|
+
'### Manual Fixes Needed ###',
|
|
84
|
+
'The configuration cannot be automatically fixed, please do the following first:',
|
|
85
|
+
], manualIssues);
|
|
86
|
+
await handleIssues([
|
|
87
|
+
'### Optional Manual Fixes ###',
|
|
88
|
+
'To fix these optional issues, please do the following manually:',
|
|
89
|
+
], manualIssuesOptional);
|
|
90
|
+
|
|
91
|
+
if (manualIssues.length > 0) {
|
|
92
|
+
this.log.info('###');
|
|
93
|
+
this.log.info('');
|
|
94
|
+
this.log.info('Bye! Run doctor again when all manual fixes have been applied!');
|
|
95
|
+
this.log.info('');
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @param {DoctorIssue} f
|
|
103
|
+
*/
|
|
104
|
+
async runAutoFix(f) {
|
|
105
|
+
this.log.info(`### Fixing: ${f.error} ###`);
|
|
106
|
+
try {
|
|
107
|
+
await f.check.fix();
|
|
108
|
+
} catch (err) {
|
|
109
|
+
if (err.constructor.name === doctor.FixSkippedError.name) {
|
|
110
|
+
this.log.info(`### Skipped fix ###`);
|
|
111
|
+
return;
|
|
112
|
+
} else {
|
|
113
|
+
this.log.warn(`${err}`.replace(/\n$/g, ''));
|
|
114
|
+
this.log.info(`### Fix did not succeed ###`);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
this.log.info('Checking if this was fixed:');
|
|
119
|
+
const res = await f.check.diagnose();
|
|
120
|
+
if (res.ok) {
|
|
121
|
+
f.fixed = true;
|
|
122
|
+
this.log.info(` ${'\u2714'.green} ${res.message}`);
|
|
123
|
+
this.log.info(`### Fix was successfully applied ###`);
|
|
124
|
+
} else {
|
|
125
|
+
this.log.info(` ${'\u2716'.red} ${res.message}`);
|
|
126
|
+
this.log.info(`### Fix was applied but issue remains ###`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async runAutoFixes() {
|
|
131
|
+
const autoFixes = _.filter(this.foundIssues, (f) => f.check.hasAutofix());
|
|
132
|
+
for (const f of autoFixes) {
|
|
133
|
+
await this.runAutoFix(f);
|
|
134
|
+
this.log.info('');
|
|
135
|
+
}
|
|
136
|
+
if (_.find(autoFixes, (f) => !f.fixed)) {
|
|
137
|
+
// a few issues remain.
|
|
138
|
+
this.log.info('Bye! A few issues remain, fix manually and/or rerun doctor!');
|
|
139
|
+
} else {
|
|
140
|
+
// nothing left to fix.
|
|
141
|
+
this.log.info('Bye! All issues have been fixed!');
|
|
142
|
+
}
|
|
143
|
+
this.log.info('');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async run() {
|
|
147
|
+
await this.diagnose();
|
|
148
|
+
if (this.reportSuccess()) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (await this.reportManualIssues()) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
await this.runAutoFixes();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* @param {DoctorCheckResult} result
|
|
159
|
+
* @param {DoctorCheck} check
|
|
160
|
+
* @returns {DoctorIssue?}
|
|
161
|
+
*/
|
|
162
|
+
toIssue(result, check) {
|
|
163
|
+
if (result.ok) {
|
|
164
|
+
this.log.info(` ${'\u2714'.green} ${result.message}`);
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const errorMessage = result.optional
|
|
169
|
+
? ` ${'\u2716'.yellow} ${result.message}`
|
|
170
|
+
: ` ${'\u2716'.red} ${result.message}`;
|
|
171
|
+
this.log.warn(errorMessage);
|
|
172
|
+
return {
|
|
173
|
+
error: errorMessage,
|
|
174
|
+
check,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* @returns {string}
|
|
180
|
+
*/
|
|
181
|
+
buildFixMessage() {
|
|
182
|
+
return `${util.pluralize('required fix', this.issuesRequiredToFix.length, true)} needed, ` +
|
|
183
|
+
`${util.pluralize('optional fix', this.issuesOptionalToFix.length, true)} possible`;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* @returns {boolean}
|
|
188
|
+
*/
|
|
189
|
+
reportSuccess() {
|
|
190
|
+
if (this.issuesRequiredToFix.length === 0 && this.issuesOptionalToFix.length === 0) {
|
|
191
|
+
this.log.info('Everything looks good, bye!');
|
|
192
|
+
this.log.info('');
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* @typedef DoctorIssue
|
|
201
|
+
* @property {DoctorCheck} check
|
|
202
|
+
* @property {string} error
|
|
203
|
+
* @property {boolean} [fixed]
|
|
204
|
+
*/
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* @typedef {import('@appium/types').IDoctorCheck} DoctorCheck
|
|
208
|
+
* @typedef {import('@appium/types').DoctorCheckResult} DoctorCheckResult
|
|
209
|
+
*/
|
|
@@ -135,9 +135,9 @@ export class DriverConfig extends ExtensionConfig {
|
|
|
135
135
|
* Given capabilities, find a matching driver within the config. Load its class and return it along with version and driver name.
|
|
136
136
|
* @template {import('@appium/types').StringRecord} C
|
|
137
137
|
* @param {C} caps
|
|
138
|
-
* @returns {MatchedDriver}
|
|
138
|
+
* @returns {Promise<MatchedDriver>}
|
|
139
139
|
*/
|
|
140
|
-
findMatchingDriver({automationName, platformName}) {
|
|
140
|
+
async findMatchingDriver({automationName, platformName}) {
|
|
141
141
|
if (!_.isString(platformName)) {
|
|
142
142
|
throw new Error('You must include a platformName capability');
|
|
143
143
|
}
|
|
@@ -158,7 +158,7 @@ export class DriverConfig extends ExtensionConfig {
|
|
|
158
158
|
);
|
|
159
159
|
log.info(`The '${driverName}' driver was installed and matched caps.`);
|
|
160
160
|
log.info(`Will require it at ${this.getInstallPath(driverName)}`);
|
|
161
|
-
const driver = this.
|
|
161
|
+
const driver = await this.requireAsync(driverName);
|
|
162
162
|
if (!driver) {
|
|
163
163
|
throw new Error(
|
|
164
164
|
`Driver '${driverName}' did not export a class with name '${mainClass}'. Contact the author of the driver!`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {util} from '@appium/support';
|
|
1
|
+
import {util, fs, system} from '@appium/support';
|
|
2
2
|
import B from 'bluebird';
|
|
3
3
|
import _ from 'lodash';
|
|
4
4
|
import path from 'path';
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
isAllowedSchemaFileExtension,
|
|
13
13
|
registerSchema,
|
|
14
14
|
} from '../schema/schema';
|
|
15
|
+
import { pathToFileURL } from 'url';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* "npm" install type
|
|
@@ -554,28 +555,45 @@ export class ExtensionConfig {
|
|
|
554
555
|
}
|
|
555
556
|
|
|
556
557
|
/**
|
|
557
|
-
*
|
|
558
|
+
*
|
|
558
559
|
* @param {ExtName<ExtType>} extName
|
|
559
|
-
* @returns {
|
|
560
|
+
* @returns {Promise<[string, string]>}
|
|
560
561
|
*/
|
|
561
|
-
|
|
562
|
+
async _resolveExtension(extName) {
|
|
562
563
|
const {mainClass} = this.installedExtensions[extName];
|
|
563
|
-
const
|
|
564
|
-
|
|
565
|
-
let
|
|
564
|
+
const moduleRoot = this.getInstallPath(extName);
|
|
565
|
+
const packageJsonPath = path.join(moduleRoot, 'package.json');
|
|
566
|
+
let entryPointPath;
|
|
566
567
|
try {
|
|
567
|
-
|
|
568
|
-
} catch (
|
|
569
|
-
throw new ReferenceError(`Could not find a ${this.extensionType} installed at ${
|
|
568
|
+
entryPointPath = JSON.parse(await fs.readFile(packageJsonPath, 'utf8')).main ?? 'index.js';
|
|
569
|
+
} catch (e) {
|
|
570
|
+
throw new ReferenceError(`Could not find a ${this.extensionType} installed at ${moduleRoot}`);
|
|
571
|
+
}
|
|
572
|
+
if (entryPointPath) {
|
|
573
|
+
entryPointPath = path.resolve(moduleRoot, entryPointPath);
|
|
574
|
+
} else {
|
|
575
|
+
throw new ReferenceError(`Cannot find a valid ${this.extensionType} main entry point in '${packageJsonPath}'`);
|
|
570
576
|
}
|
|
571
577
|
// note: this will only reload the entry point
|
|
572
|
-
if (process.env.APPIUM_RELOAD_EXTENSIONS && require.cache[
|
|
573
|
-
log.debug(`Removing ${
|
|
574
|
-
delete require.cache[
|
|
578
|
+
if (process.env.APPIUM_RELOAD_EXTENSIONS && require.cache[entryPointPath]) {
|
|
579
|
+
log.debug(`Removing ${entryPointPath} from require cache`);
|
|
580
|
+
delete require.cache[entryPointPath];
|
|
575
581
|
}
|
|
582
|
+
return [entryPointPath, mainClass];
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Loads extension asynchronously and returns its main class (constructor)
|
|
587
|
+
*
|
|
588
|
+
* @param {ExtName<ExtType>} extName
|
|
589
|
+
* @returns {Promise<ExtClass<ExtType>>}
|
|
590
|
+
*/
|
|
591
|
+
async requireAsync(extName) {
|
|
592
|
+
const [reqPath, mainClass] = await this._resolveExtension(extName);
|
|
576
593
|
log.debug(`Requiring ${this.extensionType} at ${reqPath}`);
|
|
577
|
-
//
|
|
578
|
-
const
|
|
594
|
+
// https://github.com/nodejs/node/issues/31710
|
|
595
|
+
const importPath = system.isWindows() ? pathToFileURL(reqPath).href : reqPath;
|
|
596
|
+
const MainClass = (await import(importPath))[mainClass];
|
|
579
597
|
if (!MainClass) {
|
|
580
598
|
throw new ReferenceError(
|
|
581
599
|
`Could not find a class named "${mainClass}" exported by ${this.extensionType} "${extName}"`
|
package/lib/extension/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import {USE_ALL_PLUGINS} from '../constants';
|
|
|
3
3
|
import log from '../logger';
|
|
4
4
|
import {DriverConfig} from './driver-config';
|
|
5
5
|
import {Manifest} from './manifest';
|
|
6
|
+
import {timing} from '@appium/support';
|
|
6
7
|
import {PluginConfig} from './plugin-config';
|
|
7
8
|
import B from 'bluebird';
|
|
8
9
|
|
|
@@ -27,6 +28,47 @@ export async function loadExtensions(appiumHome) {
|
|
|
27
28
|
return {driverConfig, pluginConfig};
|
|
28
29
|
}
|
|
29
30
|
|
|
31
|
+
/**
|
|
32
|
+
* @template {'driver'|'plugin'} TExtType
|
|
33
|
+
* @param {TExtType} extType
|
|
34
|
+
* @param {import('./extension-config').ExtensionConfig} config
|
|
35
|
+
* @param {string[]} extNames
|
|
36
|
+
* @param {number} asyncImportChunkSize
|
|
37
|
+
* @returns {Promise<[TExtType extends 'driver' ? DriverClass : PluginClass, string][]>}
|
|
38
|
+
*/
|
|
39
|
+
async function importExtensions(extType, config, extNames, asyncImportChunkSize) {
|
|
40
|
+
/** @type {B[]} */
|
|
41
|
+
const allPromises = [];
|
|
42
|
+
/** @type {B[]} */
|
|
43
|
+
const activePromisesChunk = [];
|
|
44
|
+
for (const extName of extNames) {
|
|
45
|
+
_.remove(activePromisesChunk, (p) => p.isFulfilled());
|
|
46
|
+
if (activePromisesChunk.length >= asyncImportChunkSize) {
|
|
47
|
+
await B.any(activePromisesChunk);
|
|
48
|
+
}
|
|
49
|
+
const promise = B.resolve((async () => {
|
|
50
|
+
log.info(`Attempting to load ${extType} ${extName}...`);
|
|
51
|
+
const timer = new timing.Timer().start();
|
|
52
|
+
try {
|
|
53
|
+
const extClass = await config.requireAsync(extName);
|
|
54
|
+
log.debug(`${extClass.name} has been successfully loaded in ${timer.getDuration().asSeconds.toFixed(3)}s`);
|
|
55
|
+
return extClass;
|
|
56
|
+
} catch (err) {
|
|
57
|
+
log.error(
|
|
58
|
+
`Could not load ${extType} '${extName}', so it will not be available. Error ` +
|
|
59
|
+
`in loading the ${extType} was: ${err.message}`
|
|
60
|
+
);
|
|
61
|
+
log.debug(err.stack);
|
|
62
|
+
}
|
|
63
|
+
})());
|
|
64
|
+
activePromisesChunk.push(promise);
|
|
65
|
+
allPromises.push(promise);
|
|
66
|
+
}
|
|
67
|
+
return /** @type {[TExtType extends 'driver' ? DriverClass : PluginClass, string][]} */ (
|
|
68
|
+
_.zip(await B.all(allPromises), extNames).filter(([extClass,]) => Boolean(extClass))
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
30
72
|
/**
|
|
31
73
|
* Find any plugin name which has been installed, and which has been requested for activation by
|
|
32
74
|
* using the --use-plugins flag, and turn each one into its class, so we can send them as objects
|
|
@@ -34,10 +76,15 @@ export async function loadExtensions(appiumHome) {
|
|
|
34
76
|
* to wrap command execution
|
|
35
77
|
*
|
|
36
78
|
* @param {import('./plugin-config').PluginConfig} pluginConfig - a plugin extension config
|
|
79
|
+
* @param {number} maxParallelImports the maximum amount of plugins to import in parallel
|
|
37
80
|
* @param {string[]} usePlugins
|
|
38
|
-
* @returns {PluginNameMap} Mapping of PluginClass to name
|
|
81
|
+
* @returns {Promise<PluginNameMap>} Mapping of PluginClass to name
|
|
39
82
|
*/
|
|
40
|
-
export function getActivePlugins(pluginConfig, usePlugins = []) {
|
|
83
|
+
export async function getActivePlugins(pluginConfig, maxParallelImports, usePlugins = []) {
|
|
84
|
+
if (_.isEmpty(usePlugins)) {
|
|
85
|
+
return new Map();
|
|
86
|
+
}
|
|
87
|
+
|
|
41
88
|
/** @type {string[]} */
|
|
42
89
|
let filteredPluginNames = [];
|
|
43
90
|
if (usePlugins.length === 1 && usePlugins[0] === USE_ALL_PLUGINS) {
|
|
@@ -52,31 +99,17 @@ export function getActivePlugins(pluginConfig, usePlugins = []) {
|
|
|
52
99
|
`The reserved plugin name '${pluginName}' cannot be combined with other names.`
|
|
53
100
|
);
|
|
54
101
|
} else {
|
|
102
|
+
const suffix = _.isEmpty(pluginConfig.installedExtensions)
|
|
103
|
+
? `You don't have any plugins installed yet.`
|
|
104
|
+
: `Only the following ${_.size(pluginConfig.installedExtensions) === 1 ? `plugin is` : `plugins are`} ` +
|
|
105
|
+
`available: ${_.keys(pluginConfig.installedExtensions)}`;
|
|
55
106
|
throw new Error(
|
|
56
|
-
`Could not load the plugin '${pluginName}' because it is not installed. `
|
|
57
|
-
`Only the following plugins are available: ${_.keys(pluginConfig.installedExtensions)}`
|
|
107
|
+
`Could not load the plugin '${pluginName}' because it is not installed. ${suffix}`
|
|
58
108
|
);
|
|
59
109
|
}
|
|
60
110
|
}
|
|
61
111
|
}
|
|
62
|
-
return new Map(
|
|
63
|
-
_.compact(
|
|
64
|
-
filteredPluginNames
|
|
65
|
-
.map((pluginName) => {
|
|
66
|
-
try {
|
|
67
|
-
log.info(`Attempting to load plugin ${pluginName}...`);
|
|
68
|
-
const PluginClass = pluginConfig.require(pluginName);
|
|
69
|
-
return [PluginClass, pluginName];
|
|
70
|
-
} catch (err) {
|
|
71
|
-
log.error(
|
|
72
|
-
`Could not load plugin '${pluginName}', so it will not be available. Error ` +
|
|
73
|
-
`in loading the plugin was: ${err.message}`
|
|
74
|
-
);
|
|
75
|
-
log.debug(err.stack);
|
|
76
|
-
}
|
|
77
|
-
})
|
|
78
|
-
)
|
|
79
|
-
);
|
|
112
|
+
return new Map(await importExtensions('plugin', pluginConfig, filteredPluginNames, maxParallelImports));
|
|
80
113
|
}
|
|
81
114
|
|
|
82
115
|
/**
|
|
@@ -85,29 +118,33 @@ export function getActivePlugins(pluginConfig, usePlugins = []) {
|
|
|
85
118
|
* If the --drivers flag was given, this method only loads the given drivers.
|
|
86
119
|
*
|
|
87
120
|
* @param {import('./driver-config').DriverConfig} driverConfig - a driver extension config
|
|
121
|
+
* @param {number} maxParallelImports the maximum amount of plugins to import in parallel
|
|
88
122
|
* @param {string[]} [useDrivers] - optional list of drivers to load
|
|
89
|
-
* @returns {DriverNameMap}
|
|
123
|
+
* @returns {Promise<DriverNameMap>}
|
|
90
124
|
*/
|
|
91
|
-
export function getActiveDrivers(driverConfig, useDrivers = []) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
125
|
+
export async function getActiveDrivers(driverConfig, maxParallelImports, useDrivers = []) {
|
|
126
|
+
/** @type {string[]} */
|
|
127
|
+
let filteredDriverNames = [];
|
|
128
|
+
if (_.isEmpty(useDrivers)) {
|
|
129
|
+
// load all drivers if none are requested
|
|
130
|
+
filteredDriverNames = _.keys(driverConfig.installedExtensions);
|
|
131
|
+
} else {
|
|
132
|
+
// Load drivers in the same order that was used while enumerating them
|
|
133
|
+
for (const driverName of useDrivers) {
|
|
134
|
+
if (driverName in driverConfig.installedExtensions) {
|
|
135
|
+
filteredDriverNames.push(driverName);
|
|
136
|
+
} else {
|
|
137
|
+
const suffix = _.isEmpty(driverConfig.installedExtensions)
|
|
138
|
+
? `You don't have any drivers installed yet.`
|
|
139
|
+
: `Only the following ${_.size(driverConfig.installedExtensions) === 1 ? `driver is` : `drivers are`} ` +
|
|
140
|
+
`available: ${_.keys(driverConfig.installedExtensions)}`;
|
|
141
|
+
throw new Error(
|
|
142
|
+
`Could not load the driver '${driverName}' because it is not installed. ${suffix}`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return new Map(await importExtensions('driver', driverConfig, filteredDriverNames, maxParallelImports));
|
|
111
148
|
}
|
|
112
149
|
|
|
113
150
|
/**
|
package/lib/grid-register.js
CHANGED
|
@@ -30,10 +30,9 @@ async function registerNode(data, addr, port, basePath) {
|
|
|
30
30
|
try {
|
|
31
31
|
data = JSON.parse(data);
|
|
32
32
|
} catch (err) {
|
|
33
|
-
logger.
|
|
33
|
+
throw logger.errorWithException(
|
|
34
34
|
`Syntax error in node configuration file ${configFilePath}: ${err.message}`
|
|
35
35
|
);
|
|
36
|
-
return;
|
|
37
36
|
}
|
|
38
37
|
}
|
|
39
38
|
|