appium 2.3.0 → 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 +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 +126 -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 +148 -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,19 @@ function receiptToManifest(receipt) {
|
|
|
31
35
|
return /** @type {ExtManifest<ExtType>} */ (_.omit(receipt, 'driverName', 'pluginName'));
|
|
32
36
|
}
|
|
33
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Fetches the remote extension version requirement
|
|
40
|
+
*
|
|
41
|
+
* @param {string} installSpec Extension name (could also contain the version suffix)
|
|
42
|
+
* @returns {Promise<[string, string|null]>}
|
|
43
|
+
*/
|
|
44
|
+
async function getRemoteExtensionVersionReq(installSpec) {
|
|
45
|
+
const allDeps = await npm.getPackageInfo(installSpec, ['peerDependencies', 'dependencies']);
|
|
46
|
+
const requiredVersionPair = _.flatMap(_.values(allDeps).map(_.toPairs))
|
|
47
|
+
.find(([name]) => name === 'appium');
|
|
48
|
+
return [npmPackage.version, requiredVersionPair ? requiredVersionPair[1] : null];
|
|
49
|
+
}
|
|
50
|
+
|
|
34
51
|
/**
|
|
35
52
|
* @template {ExtensionType} ExtType
|
|
36
53
|
*/
|
|
@@ -223,6 +240,29 @@ class ExtensionCliCommand {
|
|
|
223
240
|
return listData;
|
|
224
241
|
}
|
|
225
242
|
|
|
243
|
+
/**
|
|
244
|
+
* Checks whether the given extension is compatible with the currently installed server
|
|
245
|
+
*
|
|
246
|
+
* @param {InstallViaNpmArgs} installViaNpmOpts
|
|
247
|
+
* @returns {Promise<void>}
|
|
248
|
+
*/
|
|
249
|
+
async _checkInstallCompatibility({installSpec, pkgName, installType}) {
|
|
250
|
+
if (INSTALL_TYPE_NPM !== installType) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
await spinWith(this.isJsonOutput, `Checking if '${pkgName}' is compatible`, async () => {
|
|
255
|
+
const [serverVersion, extVersionRequirement] = await getRemoteExtensionVersionReq(installSpec);
|
|
256
|
+
if (serverVersion && extVersionRequirement && !semver.satisfies(serverVersion, extVersionRequirement)) {
|
|
257
|
+
throw this._createFatalError(
|
|
258
|
+
`'${installSpec}' cannot be installed because the server version it requires (${extVersionRequirement}) ` +
|
|
259
|
+
`does not meet the currently installed one (${serverVersion}). Please install ` +
|
|
260
|
+
`a compatible server version first.`
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
226
266
|
/**
|
|
227
267
|
* Install an extension
|
|
228
268
|
*
|
|
@@ -332,6 +372,8 @@ class ExtensionCliCommand {
|
|
|
332
372
|
);
|
|
333
373
|
}
|
|
334
374
|
|
|
375
|
+
await this._checkInstallCompatibility(installViaNpmOpts);
|
|
376
|
+
|
|
335
377
|
receipt = await this.installViaNpm(installViaNpmOpts);
|
|
336
378
|
|
|
337
379
|
// this _should_ be the same as `probablyExtName` as the one derived above unless
|
|
@@ -695,6 +737,85 @@ class ExtensionCliCommand {
|
|
|
695
737
|
});
|
|
696
738
|
}
|
|
697
739
|
|
|
740
|
+
/**
|
|
741
|
+
* Runs doctor checks for the given extension
|
|
742
|
+
*
|
|
743
|
+
* @param {DoctorOptions} opts
|
|
744
|
+
* @returns {Promise<import('@appium/types').IDoctorCheck[]>}
|
|
745
|
+
*/
|
|
746
|
+
async _doctor({installSpec}) {
|
|
747
|
+
if (!this.config.isInstalled(installSpec)) {
|
|
748
|
+
throw this._createFatalError(`The ${this.type} "${installSpec}" is not installed`);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
const moduleRoot = this.config.getInstallPath(installSpec);
|
|
752
|
+
const packageJsonPath = path.join(moduleRoot, 'package.json');
|
|
753
|
+
if (!await fs.exists(packageJsonPath)) {
|
|
754
|
+
throw this._createFatalError(
|
|
755
|
+
`No package.json could be found for "${installSpec}" ${this.type}`
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
let doctorSpec;
|
|
759
|
+
try {
|
|
760
|
+
doctorSpec = JSON.parse(await fs.readFile(packageJsonPath, 'utf8')).appium?.doctor;
|
|
761
|
+
} catch (e) {
|
|
762
|
+
throw this._createFatalError(
|
|
763
|
+
`The manifest at '${packageJsonPath}' cannot be parsed: ${e.message}`
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
if (!doctorSpec) {
|
|
767
|
+
this.log.info(`The ${this.type} "${installSpec}" does not export any doctor checks`);
|
|
768
|
+
return [];
|
|
769
|
+
}
|
|
770
|
+
if (!_.isPlainObject(doctorSpec) || !_.isArray(doctorSpec.checks)) {
|
|
771
|
+
throw this._createFatalError(
|
|
772
|
+
`The 'doctor' entry in the package manifest '${packageJsonPath}' must be a proper object ` +
|
|
773
|
+
`containing the 'checks' key with the array of script paths`
|
|
774
|
+
);
|
|
775
|
+
}
|
|
776
|
+
const paths = doctorSpec.checks.map((/** @type {string} */ p) => {
|
|
777
|
+
const scriptPath = path.resolve(moduleRoot, p);
|
|
778
|
+
if (!path.normalize(scriptPath).startsWith(path.normalize(moduleRoot))) {
|
|
779
|
+
this.log.error(
|
|
780
|
+
`The doctor check script '${p}' from the package manifest '${packageJsonPath}' must be located ` +
|
|
781
|
+
`in the '${moduleRoot}' root folder. It will be skipped`
|
|
782
|
+
);
|
|
783
|
+
return null;
|
|
784
|
+
}
|
|
785
|
+
return scriptPath;
|
|
786
|
+
}).filter(Boolean);
|
|
787
|
+
/** @type {Promise[]} */
|
|
788
|
+
const loadChecksPromises = [];
|
|
789
|
+
for (const p of paths) {
|
|
790
|
+
const promise = (async () => {
|
|
791
|
+
// https://github.com/nodejs/node/issues/31710
|
|
792
|
+
const scriptPath = system.isWindows() ? pathToFileURL(p).href : p;
|
|
793
|
+
try {
|
|
794
|
+
return await import(scriptPath);
|
|
795
|
+
} catch (e) {
|
|
796
|
+
this.log.warn(`Unable to load doctor checks from '${p}': ${e.message}`);
|
|
797
|
+
}
|
|
798
|
+
})();
|
|
799
|
+
loadChecksPromises.push(promise);
|
|
800
|
+
}
|
|
801
|
+
const isDoctorCheck = (/** @type {any} */ x) =>
|
|
802
|
+
['diagnose', 'fix', 'hasAutofix', 'isOptional'].every((method) => _.isFunction(x?.[method]));
|
|
803
|
+
/** @type {import('@appium/types').IDoctorCheck[]} */
|
|
804
|
+
const checks = _.flatMap((await B.all(loadChecksPromises)).filter(Boolean).map(_.toPairs))
|
|
805
|
+
.map(([, value]) => value)
|
|
806
|
+
.filter(isDoctorCheck);
|
|
807
|
+
if (_.isEmpty(checks)) {
|
|
808
|
+
this.log.info(`The ${this.type} "${installSpec}" exports no valid doctor checks`);
|
|
809
|
+
return [];
|
|
810
|
+
}
|
|
811
|
+
this.log.debug(
|
|
812
|
+
`Running ${util.pluralize('doctor check', checks.length, true)} ` +
|
|
813
|
+
`for the "${installSpec}" ${this.type}`
|
|
814
|
+
);
|
|
815
|
+
await new Doctor(checks).run();
|
|
816
|
+
return checks;
|
|
817
|
+
}
|
|
818
|
+
|
|
698
819
|
/**
|
|
699
820
|
* Runs a script cached inside the `scripts` field under `appium`
|
|
700
821
|
* inside of the extension's `package.json` file. Will throw
|
|
@@ -729,6 +850,24 @@ class ExtensionCliCommand {
|
|
|
729
850
|
);
|
|
730
851
|
}
|
|
731
852
|
|
|
853
|
+
if (!scriptName) {
|
|
854
|
+
const allScripts = _.toPairs(extScripts);
|
|
855
|
+
const root = this.config.getInstallPath(installSpec);
|
|
856
|
+
const existingScripts = await B.filter(
|
|
857
|
+
allScripts,
|
|
858
|
+
async ([, p]) => await fs.exists(path.join(root, p))
|
|
859
|
+
);
|
|
860
|
+
if (_.isEmpty(existingScripts)) {
|
|
861
|
+
this.log.info(`The ${this.type} named '${installSpec}' does not contain any scripts`);
|
|
862
|
+
} else {
|
|
863
|
+
this.log.info(`The ${this.type} named '${installSpec}' contains ` +
|
|
864
|
+
`${util.pluralize('script', existingScripts.length, true)}:`);
|
|
865
|
+
existingScripts.forEach(([name]) => this.log.info(` - ${name}`));
|
|
866
|
+
}
|
|
867
|
+
this.log.ok(`Successfully retrieved the list of scripts`.green);
|
|
868
|
+
return {};
|
|
869
|
+
}
|
|
870
|
+
|
|
732
871
|
if (!(scriptName in /** @type {Record<string,string>} */ (extScripts))) {
|
|
733
872
|
throw this._createFatalError(
|
|
734
873
|
`The ${this.type} named '${installSpec}' does not support the script: '${scriptName}'`
|
|
@@ -874,11 +1013,18 @@ export {ExtensionCliCommand as ExtensionCommand};
|
|
|
874
1013
|
* Options for {@linkcode ExtensionCliCommand._run}.
|
|
875
1014
|
* @typedef RunOptions
|
|
876
1015
|
* @property {string} installSpec - name of the extension to run a script from
|
|
877
|
-
* @property {string} scriptName - name of the script to run
|
|
1016
|
+
* @property {string} [scriptName] - name of the script to run. If not provided
|
|
1017
|
+
* then all available script names will be printed
|
|
878
1018
|
* @property {string[]} [extraArgs] - arguments to pass to the script
|
|
879
1019
|
* @property {boolean} [bufferOutput] - if true, will buffer the output of the script and return it
|
|
880
1020
|
*/
|
|
881
1021
|
|
|
1022
|
+
/**
|
|
1023
|
+
* Options for {@linkcode ExtensionCliCommand.doctor}.
|
|
1024
|
+
* @typedef DoctorOptions
|
|
1025
|
+
* @property {string} installSpec - name of the extension to run doctor checks for
|
|
1026
|
+
*/
|
|
1027
|
+
|
|
882
1028
|
/**
|
|
883
1029
|
* Return value of {@linkcode ExtensionCliCommand._run}
|
|
884
1030
|
*
|
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';
|