appium 2.3.0 → 2.4.1
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 +129 -158
- package/build/lib/appium.d.ts +72 -0
- package/build/lib/appium.d.ts.map +1 -1
- package/build/lib/appium.js +326 -0
- 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 +127 -1
- 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.d.ts +1 -1
- package/build/lib/config.d.ts.map +1 -1
- package/build/lib/config.js +25 -29
- 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/index.d.ts.map +1 -1
- package/build/lib/extension/index.js +10 -4
- package/build/lib/extension/index.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.map +1 -1
- package/build/lib/main.js +6 -0
- package/build/lib/main.js.map +1 -1
- package/build/lib/utils.d.ts +1 -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 +387 -1
- package/lib/cli/args.js +27 -2
- package/lib/cli/driver-command.js +18 -0
- package/lib/cli/extension-command.js +152 -2
- 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 +18 -24
- package/lib/constants.js +12 -0
- package/lib/doctor/doctor.js +209 -0
- package/lib/extension/index.js +10 -4
- package/lib/grid-register.js +1 -2
- package/lib/main.js +6 -0
- package/lib/utils.js +2 -1
- package/package.json +13 -13
- package/types/cli.ts +1 -1
|
@@ -66,6 +66,18 @@ export default class DriverCliCommand extends ExtensionCliCommand {
|
|
|
66
66
|
});
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Runs doctor checks for the given driver
|
|
71
|
+
*
|
|
72
|
+
* @param {DriverDoctorOptions} opts
|
|
73
|
+
* @returns {Promise<import('@appium/types').IDoctorCheck[]>}
|
|
74
|
+
*/
|
|
75
|
+
async doctor({driver}) {
|
|
76
|
+
return await super._doctor({
|
|
77
|
+
installSpec: driver,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
69
81
|
/**
|
|
70
82
|
*
|
|
71
83
|
* @param {import('./extension-command').ExtensionArgs} opts
|
|
@@ -151,3 +163,9 @@ export default class DriverCliCommand extends ExtensionCliCommand {
|
|
|
151
163
|
* @property {string} scriptName - name of the script to run
|
|
152
164
|
* @property {string[]} [extraArgs] - arguments to pass to the script
|
|
153
165
|
*/
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Options for {@linkcode DriverCliCommand.doctor}.
|
|
169
|
+
* @typedef DriverDoctorOptions
|
|
170
|
+
* @property {string} driver - name of the driver to run doctor checks for
|
|
171
|
+
*/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import B from 'bluebird';
|
|
3
3
|
import _ from 'lodash';
|
|
4
4
|
import path from 'path';
|
|
5
|
-
import {npm, util, env, console} from '@appium/support';
|
|
5
|
+
import {npm, util, env, console, fs, system} from '@appium/support';
|
|
6
6
|
import {spinWith, RingBuffer} from './utils';
|
|
7
7
|
import {
|
|
8
8
|
INSTALL_TYPE_NPM,
|
|
@@ -15,6 +15,10 @@ import {SubProcess} from 'teen_process';
|
|
|
15
15
|
import {packageDidChange} from '../extension/package-changed';
|
|
16
16
|
import {spawn} from 'child_process';
|
|
17
17
|
import {inspect} from 'node:util';
|
|
18
|
+
import {pathToFileURL} from 'url';
|
|
19
|
+
import {Doctor} from '../doctor/doctor';
|
|
20
|
+
import {npmPackage} from '../utils';
|
|
21
|
+
import semver from 'semver';
|
|
18
22
|
|
|
19
23
|
const UPDATE_ALL = 'installed';
|
|
20
24
|
|
|
@@ -31,6 +35,23 @@ function receiptToManifest(receipt) {
|
|
|
31
35
|
return /** @type {ExtManifest<ExtType>} */ (_.omit(receipt, 'driverName', 'pluginName'));
|
|
32
36
|
}
|
|
33
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Fetches the remote extension version requirements
|
|
40
|
+
*
|
|
41
|
+
* @param {string} pkgName Extension name
|
|
42
|
+
* @param {string} [pkgVer] Extension version (if not provided then the latest is assumed)
|
|
43
|
+
* @returns {Promise<[string, string|null]>}
|
|
44
|
+
*/
|
|
45
|
+
async function getRemoteExtensionVersionReq(pkgName, pkgVer) {
|
|
46
|
+
const allDeps = await npm.getPackageInfo(
|
|
47
|
+
`${pkgName}${pkgVer ? `@${pkgVer}` : ``}`,
|
|
48
|
+
['peerDependencies', 'dependencies']
|
|
49
|
+
);
|
|
50
|
+
const requiredVersionPair = _.flatMap(_.values(allDeps).map(_.toPairs))
|
|
51
|
+
.find(([name]) => name === 'appium');
|
|
52
|
+
return [npmPackage.version, requiredVersionPair ? requiredVersionPair[1] : null];
|
|
53
|
+
}
|
|
54
|
+
|
|
34
55
|
/**
|
|
35
56
|
* @template {ExtensionType} ExtType
|
|
36
57
|
*/
|
|
@@ -223,6 +244,29 @@ class ExtensionCliCommand {
|
|
|
223
244
|
return listData;
|
|
224
245
|
}
|
|
225
246
|
|
|
247
|
+
/**
|
|
248
|
+
* Checks whether the given extension is compatible with the currently installed server
|
|
249
|
+
*
|
|
250
|
+
* @param {InstallViaNpmArgs} installViaNpmOpts
|
|
251
|
+
* @returns {Promise<void>}
|
|
252
|
+
*/
|
|
253
|
+
async _checkInstallCompatibility({installSpec, pkgName, pkgVer, installType}) {
|
|
254
|
+
if (INSTALL_TYPE_NPM !== installType) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
await spinWith(this.isJsonOutput, `Checking if '${pkgName}' is compatible`, async () => {
|
|
259
|
+
const [serverVersion, extVersionRequirement] = await getRemoteExtensionVersionReq(pkgName, pkgVer);
|
|
260
|
+
if (serverVersion && extVersionRequirement && !semver.satisfies(serverVersion, extVersionRequirement)) {
|
|
261
|
+
throw this._createFatalError(
|
|
262
|
+
`'${installSpec}' cannot be installed because the server version it requires (${extVersionRequirement}) ` +
|
|
263
|
+
`does not meet the currently installed one (${serverVersion}). Please install ` +
|
|
264
|
+
`a compatible server version first.`
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
226
270
|
/**
|
|
227
271
|
* Install an extension
|
|
228
272
|
*
|
|
@@ -332,6 +376,8 @@ class ExtensionCliCommand {
|
|
|
332
376
|
);
|
|
333
377
|
}
|
|
334
378
|
|
|
379
|
+
await this._checkInstallCompatibility(installViaNpmOpts);
|
|
380
|
+
|
|
335
381
|
receipt = await this.installViaNpm(installViaNpmOpts);
|
|
336
382
|
|
|
337
383
|
// this _should_ be the same as `probablyExtName` as the one derived above unless
|
|
@@ -695,6 +741,85 @@ class ExtensionCliCommand {
|
|
|
695
741
|
});
|
|
696
742
|
}
|
|
697
743
|
|
|
744
|
+
/**
|
|
745
|
+
* Runs doctor checks for the given extension
|
|
746
|
+
*
|
|
747
|
+
* @param {DoctorOptions} opts
|
|
748
|
+
* @returns {Promise<import('@appium/types').IDoctorCheck[]>}
|
|
749
|
+
*/
|
|
750
|
+
async _doctor({installSpec}) {
|
|
751
|
+
if (!this.config.isInstalled(installSpec)) {
|
|
752
|
+
throw this._createFatalError(`The ${this.type} "${installSpec}" is not installed`);
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
const moduleRoot = this.config.getInstallPath(installSpec);
|
|
756
|
+
const packageJsonPath = path.join(moduleRoot, 'package.json');
|
|
757
|
+
if (!await fs.exists(packageJsonPath)) {
|
|
758
|
+
throw this._createFatalError(
|
|
759
|
+
`No package.json could be found for "${installSpec}" ${this.type}`
|
|
760
|
+
);
|
|
761
|
+
}
|
|
762
|
+
let doctorSpec;
|
|
763
|
+
try {
|
|
764
|
+
doctorSpec = JSON.parse(await fs.readFile(packageJsonPath, 'utf8')).appium?.doctor;
|
|
765
|
+
} catch (e) {
|
|
766
|
+
throw this._createFatalError(
|
|
767
|
+
`The manifest at '${packageJsonPath}' cannot be parsed: ${e.message}`
|
|
768
|
+
);
|
|
769
|
+
}
|
|
770
|
+
if (!doctorSpec) {
|
|
771
|
+
this.log.info(`The ${this.type} "${installSpec}" does not export any doctor checks`);
|
|
772
|
+
return [];
|
|
773
|
+
}
|
|
774
|
+
if (!_.isPlainObject(doctorSpec) || !_.isArray(doctorSpec.checks)) {
|
|
775
|
+
throw this._createFatalError(
|
|
776
|
+
`The 'doctor' entry in the package manifest '${packageJsonPath}' must be a proper object ` +
|
|
777
|
+
`containing the 'checks' key with the array of script paths`
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
const paths = doctorSpec.checks.map((/** @type {string} */ p) => {
|
|
781
|
+
const scriptPath = path.resolve(moduleRoot, p);
|
|
782
|
+
if (!path.normalize(scriptPath).startsWith(path.normalize(moduleRoot))) {
|
|
783
|
+
this.log.error(
|
|
784
|
+
`The doctor check script '${p}' from the package manifest '${packageJsonPath}' must be located ` +
|
|
785
|
+
`in the '${moduleRoot}' root folder. It will be skipped`
|
|
786
|
+
);
|
|
787
|
+
return null;
|
|
788
|
+
}
|
|
789
|
+
return scriptPath;
|
|
790
|
+
}).filter(Boolean);
|
|
791
|
+
/** @type {Promise[]} */
|
|
792
|
+
const loadChecksPromises = [];
|
|
793
|
+
for (const p of paths) {
|
|
794
|
+
const promise = (async () => {
|
|
795
|
+
// https://github.com/nodejs/node/issues/31710
|
|
796
|
+
const scriptPath = system.isWindows() ? pathToFileURL(p).href : p;
|
|
797
|
+
try {
|
|
798
|
+
return await import(scriptPath);
|
|
799
|
+
} catch (e) {
|
|
800
|
+
this.log.warn(`Unable to load doctor checks from '${p}': ${e.message}`);
|
|
801
|
+
}
|
|
802
|
+
})();
|
|
803
|
+
loadChecksPromises.push(promise);
|
|
804
|
+
}
|
|
805
|
+
const isDoctorCheck = (/** @type {any} */ x) =>
|
|
806
|
+
['diagnose', 'fix', 'hasAutofix', 'isOptional'].every((method) => _.isFunction(x?.[method]));
|
|
807
|
+
/** @type {import('@appium/types').IDoctorCheck[]} */
|
|
808
|
+
const checks = _.flatMap((await B.all(loadChecksPromises)).filter(Boolean).map(_.toPairs))
|
|
809
|
+
.map(([, value]) => value)
|
|
810
|
+
.filter(isDoctorCheck);
|
|
811
|
+
if (_.isEmpty(checks)) {
|
|
812
|
+
this.log.info(`The ${this.type} "${installSpec}" exports no valid doctor checks`);
|
|
813
|
+
return [];
|
|
814
|
+
}
|
|
815
|
+
this.log.debug(
|
|
816
|
+
`Running ${util.pluralize('doctor check', checks.length, true)} ` +
|
|
817
|
+
`for the "${installSpec}" ${this.type}`
|
|
818
|
+
);
|
|
819
|
+
await new Doctor(checks).run();
|
|
820
|
+
return checks;
|
|
821
|
+
}
|
|
822
|
+
|
|
698
823
|
/**
|
|
699
824
|
* Runs a script cached inside the `scripts` field under `appium`
|
|
700
825
|
* inside of the extension's `package.json` file. Will throw
|
|
@@ -729,6 +854,24 @@ class ExtensionCliCommand {
|
|
|
729
854
|
);
|
|
730
855
|
}
|
|
731
856
|
|
|
857
|
+
if (!scriptName) {
|
|
858
|
+
const allScripts = _.toPairs(extScripts);
|
|
859
|
+
const root = this.config.getInstallPath(installSpec);
|
|
860
|
+
const existingScripts = await B.filter(
|
|
861
|
+
allScripts,
|
|
862
|
+
async ([, p]) => await fs.exists(path.join(root, p))
|
|
863
|
+
);
|
|
864
|
+
if (_.isEmpty(existingScripts)) {
|
|
865
|
+
this.log.info(`The ${this.type} named '${installSpec}' does not contain any scripts`);
|
|
866
|
+
} else {
|
|
867
|
+
this.log.info(`The ${this.type} named '${installSpec}' contains ` +
|
|
868
|
+
`${util.pluralize('script', existingScripts.length, true)}:`);
|
|
869
|
+
existingScripts.forEach(([name]) => this.log.info(` - ${name}`));
|
|
870
|
+
}
|
|
871
|
+
this.log.ok(`Successfully retrieved the list of scripts`.green);
|
|
872
|
+
return {};
|
|
873
|
+
}
|
|
874
|
+
|
|
732
875
|
if (!(scriptName in /** @type {Record<string,string>} */ (extScripts))) {
|
|
733
876
|
throw this._createFatalError(
|
|
734
877
|
`The ${this.type} named '${installSpec}' does not support the script: '${scriptName}'`
|
|
@@ -874,11 +1017,18 @@ export {ExtensionCliCommand as ExtensionCommand};
|
|
|
874
1017
|
* Options for {@linkcode ExtensionCliCommand._run}.
|
|
875
1018
|
* @typedef RunOptions
|
|
876
1019
|
* @property {string} installSpec - name of the extension to run a script from
|
|
877
|
-
* @property {string} scriptName - name of the script to run
|
|
1020
|
+
* @property {string} [scriptName] - name of the script to run. If not provided
|
|
1021
|
+
* then all available script names will be printed
|
|
878
1022
|
* @property {string[]} [extraArgs] - arguments to pass to the script
|
|
879
1023
|
* @property {boolean} [bufferOutput] - if true, will buffer the output of the script and return it
|
|
880
1024
|
*/
|
|
881
1025
|
|
|
1026
|
+
/**
|
|
1027
|
+
* Options for {@linkcode ExtensionCliCommand.doctor}.
|
|
1028
|
+
* @typedef DoctorOptions
|
|
1029
|
+
* @property {string} installSpec - name of the extension to run doctor checks for
|
|
1030
|
+
*/
|
|
1031
|
+
|
|
882
1032
|
/**
|
|
883
1033
|
* Return value of {@linkcode ExtensionCliCommand._run}
|
|
884
1034
|
*
|
package/lib/cli/parser.js
CHANGED
|
@@ -2,7 +2,17 @@ import {fs} from '@appium/support';
|
|
|
2
2
|
import {ArgumentParser} from 'argparse';
|
|
3
3
|
import _ from 'lodash';
|
|
4
4
|
import path from 'path';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
DRIVER_TYPE,
|
|
7
|
+
EXT_SUBCOMMAND_DOCTOR,
|
|
8
|
+
EXT_SUBCOMMAND_INSTALL,
|
|
9
|
+
EXT_SUBCOMMAND_LIST,
|
|
10
|
+
EXT_SUBCOMMAND_RUN,
|
|
11
|
+
EXT_SUBCOMMAND_UNINSTALL,
|
|
12
|
+
EXT_SUBCOMMAND_UPDATE,
|
|
13
|
+
PLUGIN_TYPE,
|
|
14
|
+
SERVER_SUBCOMMAND
|
|
15
|
+
} from '../constants';
|
|
6
16
|
import {finalizeSchema, getArgSpec, hasArgSpec} from '../schema';
|
|
7
17
|
import {rootDir} from '../config';
|
|
8
18
|
import {getExtensionArgs, getServerArgs} from './args';
|
|
@@ -191,8 +201,7 @@ class ArgParser {
|
|
|
191
201
|
|
|
192
202
|
const serverArgs = getServerArgs();
|
|
193
203
|
for (const [flagsOrNames, opts] of serverArgs) {
|
|
194
|
-
// TS doesn't like the spread operator here.
|
|
195
|
-
// @ts-ignore
|
|
204
|
+
// @ts-ignore TS doesn't like the spread operator here.
|
|
196
205
|
serverParser.add_argument(...flagsOrNames, {...opts});
|
|
197
206
|
}
|
|
198
207
|
|
|
@@ -221,33 +230,38 @@ class ArgParser {
|
|
|
221
230
|
*/
|
|
222
231
|
const parserSpecs = [
|
|
223
232
|
{
|
|
224
|
-
command:
|
|
233
|
+
command: EXT_SUBCOMMAND_LIST,
|
|
225
234
|
args: extensionArgs[type].list,
|
|
226
235
|
help: `List available and installed ${type}s`,
|
|
227
236
|
aliases: ['ls'],
|
|
228
237
|
},
|
|
229
238
|
{
|
|
230
|
-
command:
|
|
239
|
+
command: EXT_SUBCOMMAND_INSTALL,
|
|
231
240
|
args: extensionArgs[type].install,
|
|
232
241
|
help: `Install a ${type}`,
|
|
233
242
|
},
|
|
234
243
|
{
|
|
235
|
-
command:
|
|
244
|
+
command: EXT_SUBCOMMAND_UNINSTALL,
|
|
236
245
|
args: extensionArgs[type].uninstall,
|
|
237
246
|
help: `Uninstall a ${type}`,
|
|
238
247
|
},
|
|
239
248
|
{
|
|
240
|
-
command:
|
|
249
|
+
command: EXT_SUBCOMMAND_UPDATE,
|
|
241
250
|
args: extensionArgs[type].update,
|
|
242
251
|
help: `Update installed ${type}s to the latest version`,
|
|
243
252
|
},
|
|
244
253
|
{
|
|
245
|
-
command:
|
|
254
|
+
command: EXT_SUBCOMMAND_RUN,
|
|
246
255
|
args: extensionArgs[type].run,
|
|
247
256
|
help:
|
|
248
257
|
`Run a script (defined inside the ${type}'s package.json under the ` +
|
|
249
258
|
`“scripts” field inside the “appium” field) from an installed ${type}`,
|
|
250
259
|
},
|
|
260
|
+
{
|
|
261
|
+
command: EXT_SUBCOMMAND_DOCTOR,
|
|
262
|
+
args: extensionArgs[type].doctor,
|
|
263
|
+
help: `Run doctor checks (if any defined) for the given ${type}`,
|
|
264
|
+
},
|
|
251
265
|
];
|
|
252
266
|
|
|
253
267
|
for (const {command, args, help, aliases} of parserSpecs) {
|
|
@@ -65,6 +65,18 @@ export default class PluginCliCommand extends ExtensionCliCommand {
|
|
|
65
65
|
});
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Runs doctor checks for the given plugin
|
|
70
|
+
*
|
|
71
|
+
* @param {PluginDoctorOptions} opts
|
|
72
|
+
* @returns {Promise<import('@appium/types').IDoctorCheck[]>}
|
|
73
|
+
*/
|
|
74
|
+
async doctor({plugin}) {
|
|
75
|
+
return await super._doctor({
|
|
76
|
+
installSpec: plugin,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
68
80
|
/**
|
|
69
81
|
*
|
|
70
82
|
* @param {import('./extension-command').ExtensionArgs} opts
|
|
@@ -141,3 +153,9 @@ export default class PluginCliCommand extends ExtensionCliCommand {
|
|
|
141
153
|
* @property {string} scriptName - name of the script to run
|
|
142
154
|
* @property {string[]} [extraArgs] - arguments to pass to the script
|
|
143
155
|
*/
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Options for {@linkcode PluginCliCommand.doctor}.
|
|
159
|
+
* @typedef PluginDoctorOptions
|
|
160
|
+
* @property {string} plugin - name of the plugin to run doctor checks for
|
|
161
|
+
*/
|
package/lib/cli/utils.js
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
import ora from 'ora';
|
|
4
4
|
|
|
5
|
-
const JSON_SPACES = 4;
|
|
5
|
+
export const JSON_SPACES = 4;
|
|
6
6
|
|
|
7
7
|
/***
|
|
8
8
|
* Log an error to the console and exit the process.
|
|
9
9
|
* @param {boolean} json - whether we should log json or text
|
|
10
10
|
* @param {any} msg - error message, object, Error instance, etc.
|
|
11
11
|
*/
|
|
12
|
-
function errAndQuit(json, msg) {
|
|
12
|
+
export function errAndQuit(json, msg) {
|
|
13
13
|
if (json) {
|
|
14
14
|
console.log(JSON.stringify({error: `${msg}`}, null, JSON_SPACES));
|
|
15
15
|
} else {
|
|
@@ -26,7 +26,7 @@ function errAndQuit(json, msg) {
|
|
|
26
26
|
* @param {boolean} json - whether we are in json mode (and should therefore not log)
|
|
27
27
|
* @param {string} msg - string to log
|
|
28
28
|
*/
|
|
29
|
-
function log(json, msg) {
|
|
29
|
+
export function log(json, msg) {
|
|
30
30
|
!json && console.log(msg);
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -36,7 +36,7 @@ function log(json, msg) {
|
|
|
36
36
|
* @param {string} msg - string to log
|
|
37
37
|
* @param {function} fn - function to wrap with spinning
|
|
38
38
|
*/
|
|
39
|
-
async function spinWith(json, msg, fn) {
|
|
39
|
+
export async function spinWith(json, msg, fn) {
|
|
40
40
|
if (json) {
|
|
41
41
|
return await fn();
|
|
42
42
|
}
|
|
@@ -52,7 +52,7 @@ async function spinWith(json, msg, fn) {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
class RingBuffer {
|
|
55
|
+
export class RingBuffer {
|
|
56
56
|
constructor(size = 50) {
|
|
57
57
|
this.size = size;
|
|
58
58
|
this.buffer = [];
|
|
@@ -70,5 +70,3 @@ class RingBuffer {
|
|
|
70
70
|
this.buffer.push(item);
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
-
|
|
74
|
-
export {errAndQuit, log, spinWith, JSON_SPACES, RingBuffer};
|
package/lib/config.js
CHANGED
|
@@ -4,17 +4,14 @@ import {system, fs} from '@appium/support';
|
|
|
4
4
|
import axios from 'axios';
|
|
5
5
|
import {exec} from 'teen_process';
|
|
6
6
|
import semver from 'semver';
|
|
7
|
-
import findUp from 'find-up';
|
|
8
7
|
import os from 'node:os';
|
|
8
|
+
import {npmPackage} from './utils';
|
|
9
9
|
import {getDefaultsForSchema, getAllArgSpecs} from './schema/schema';
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
const APPIUM_VER = npmPackage.version;
|
|
11
|
+
export const APPIUM_VER = npmPackage.version;
|
|
14
12
|
const ENGINES = /** @type {Record<string,string>} */ (npmPackage.engines);
|
|
15
13
|
const MIN_NODE_VERSION = ENGINES.node;
|
|
16
14
|
|
|
17
|
-
const GIT_META_ROOT = '.git';
|
|
18
15
|
const GIT_BINARY = `git${system.isWindows() ? '.exe' : ''}`;
|
|
19
16
|
const GITHUB_API = 'https://api.github.com/repos/appium/appium';
|
|
20
17
|
|
|
@@ -44,27 +41,25 @@ async function updateBuildInfo(useGithubApiFallback = false) {
|
|
|
44
41
|
}
|
|
45
42
|
}
|
|
46
43
|
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return await findUp(GIT_META_ROOT, {cwd: rootDir, type: 'directory'});
|
|
56
|
-
}
|
|
44
|
+
/** @type {() => Promise<string?>} */
|
|
45
|
+
const getFullGitPath = _.memoize(async function getFullGitPath() {
|
|
46
|
+
try {
|
|
47
|
+
return await fs.which(GIT_BINARY);
|
|
48
|
+
} catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
57
52
|
|
|
58
53
|
/**
|
|
59
54
|
* @param {boolean} [useGithubApiFallback]
|
|
60
55
|
* @returns {Promise<string?>}
|
|
61
56
|
*/
|
|
62
57
|
async function getGitRev(useGithubApiFallback = false) {
|
|
63
|
-
const
|
|
64
|
-
if (
|
|
58
|
+
const fullGitPath = await getFullGitPath();
|
|
59
|
+
if (fullGitPath) {
|
|
65
60
|
try {
|
|
66
|
-
const {stdout} = await exec(
|
|
67
|
-
cwd:
|
|
61
|
+
const {stdout} = await exec(fullGitPath, ['rev-parse', 'HEAD'], {
|
|
62
|
+
cwd: __dirname,
|
|
68
63
|
});
|
|
69
64
|
return stdout.trim();
|
|
70
65
|
} catch (ign) {}
|
|
@@ -94,11 +89,11 @@ async function getGitRev(useGithubApiFallback = false) {
|
|
|
94
89
|
* @returns {Promise<string?>}
|
|
95
90
|
*/
|
|
96
91
|
async function getGitTimestamp(commitSha, useGithubApiFallback = false) {
|
|
97
|
-
const
|
|
98
|
-
if (
|
|
92
|
+
const fullGitPath = await getFullGitPath();
|
|
93
|
+
if (fullGitPath) {
|
|
99
94
|
try {
|
|
100
|
-
const {stdout} = await exec(
|
|
101
|
-
cwd:
|
|
95
|
+
const {stdout} = await exec(fullGitPath, ['show', '-s', '--format=%ci', commitSha], {
|
|
96
|
+
cwd: __dirname,
|
|
102
97
|
});
|
|
103
98
|
return stdout.trim();
|
|
104
99
|
} catch (ign) {}
|
|
@@ -321,7 +316,6 @@ export {
|
|
|
321
316
|
showBuildInfo,
|
|
322
317
|
getNonDefaultServerArgs,
|
|
323
318
|
getGitRev,
|
|
324
|
-
APPIUM_VER,
|
|
325
319
|
updateBuildInfo,
|
|
326
320
|
showConfig,
|
|
327
321
|
rootDir,
|
package/lib/constants.js
CHANGED
|
@@ -64,6 +64,7 @@ export const EXT_SUBCOMMAND_INSTALL = 'install';
|
|
|
64
64
|
export const EXT_SUBCOMMAND_UNINSTALL = 'uninstall';
|
|
65
65
|
export const EXT_SUBCOMMAND_UPDATE = 'update';
|
|
66
66
|
export const EXT_SUBCOMMAND_RUN = 'run';
|
|
67
|
+
export const EXT_SUBCOMMAND_DOCTOR = 'doctor';
|
|
67
68
|
|
|
68
69
|
/**
|
|
69
70
|
* Current revision of the manifest (`extensions.yaml`) schema
|
|
@@ -77,3 +78,14 @@ export const CURRENT_SCHEMA_REV = 4;
|
|
|
77
78
|
* memory usage, perf, and/or log output, and higher limits may be difficult to scan.
|
|
78
79
|
*/
|
|
79
80
|
export const LONG_STACKTRACE_LIMIT = 100;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Where should the bidi websocket handler live on the server?
|
|
84
|
+
*/
|
|
85
|
+
export const BIDI_BASE_PATH = '/bidi';
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The name of the event for drivers to emit when they want to send bidi events to a client over
|
|
89
|
+
* a bidi socket
|
|
90
|
+
*/
|
|
91
|
+
export const BIDI_EVENT_NAME = 'bidiEvent';
|