appium 2.0.0-beta.6 → 2.0.0-beta.60
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/LICENSE +1 -1
- package/README.md +156 -65
- package/build/lib/appium.d.ts +229 -0
- package/build/lib/appium.d.ts.map +1 -0
- package/build/lib/appium.js +678 -439
- package/build/lib/appium.js.map +1 -0
- package/build/lib/cli/args.d.ts +17 -0
- package/build/lib/cli/args.d.ts.map +1 -0
- package/build/lib/cli/args.js +263 -319
- package/build/lib/cli/args.js.map +1 -0
- package/build/lib/cli/driver-command.d.ts +102 -0
- package/build/lib/cli/driver-command.d.ts.map +1 -0
- package/build/lib/cli/driver-command.js +131 -81
- package/build/lib/cli/driver-command.js.map +1 -0
- package/build/lib/cli/extension-command.d.ts +402 -0
- package/build/lib/cli/extension-command.d.ts.map +1 -0
- package/build/lib/cli/extension-command.js +799 -383
- package/build/lib/cli/extension-command.js.map +1 -0
- package/build/lib/cli/extension.d.ts +23 -0
- package/build/lib/cli/extension.d.ts.map +1 -0
- package/build/lib/cli/extension.js +71 -54
- package/build/lib/cli/extension.js.map +1 -0
- package/build/lib/cli/parser.d.ts +84 -0
- package/build/lib/cli/parser.d.ts.map +1 -0
- package/build/lib/cli/parser.js +240 -128
- package/build/lib/cli/parser.js.map +1 -0
- package/build/lib/cli/plugin-command.d.ts +99 -0
- package/build/lib/cli/plugin-command.d.ts.map +1 -0
- package/build/lib/cli/plugin-command.js +125 -81
- package/build/lib/cli/plugin-command.js.map +1 -0
- package/build/lib/cli/utils.d.ts +29 -0
- package/build/lib/cli/utils.d.ts.map +1 -0
- package/build/lib/cli/utils.js +72 -51
- package/build/lib/cli/utils.js.map +1 -0
- package/build/lib/config-file.d.ts +100 -0
- package/build/lib/config-file.d.ts.map +1 -0
- package/build/lib/config-file.js +207 -0
- package/build/lib/config-file.js.map +1 -0
- package/build/lib/config.d.ts +49 -0
- package/build/lib/config.d.ts.map +1 -0
- package/build/lib/config.js +267 -202
- package/build/lib/config.js.map +1 -0
- package/build/lib/constants.d.ts +56 -0
- package/build/lib/constants.d.ts.map +1 -0
- package/build/lib/constants.js +73 -0
- package/build/lib/constants.js.map +1 -0
- package/build/lib/extension/driver-config.d.ts +82 -0
- package/build/lib/extension/driver-config.d.ts.map +1 -0
- package/build/lib/extension/driver-config.js +210 -0
- package/build/lib/extension/driver-config.js.map +1 -0
- package/build/lib/extension/extension-config.d.ts +270 -0
- package/build/lib/extension/extension-config.d.ts.map +1 -0
- package/build/lib/extension/extension-config.js +601 -0
- package/build/lib/extension/extension-config.js.map +1 -0
- package/build/lib/extension/index.d.ts +48 -0
- package/build/lib/extension/index.d.ts.map +1 -0
- package/build/lib/extension/index.js +105 -0
- package/build/lib/extension/index.js.map +1 -0
- 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 +134 -0
- package/build/lib/extension/manifest-migrations.js.map +1 -0
- package/build/lib/extension/manifest.d.ts +145 -0
- package/build/lib/extension/manifest.d.ts.map +1 -0
- package/build/lib/extension/manifest.js +528 -0
- package/build/lib/extension/manifest.js.map +1 -0
- package/build/lib/extension/package-changed.d.ts +11 -0
- package/build/lib/extension/package-changed.d.ts.map +1 -0
- package/build/lib/extension/package-changed.js +62 -0
- package/build/lib/extension/package-changed.js.map +1 -0
- package/build/lib/extension/plugin-config.d.ts +56 -0
- package/build/lib/extension/plugin-config.d.ts.map +1 -0
- package/build/lib/extension/plugin-config.js +102 -0
- package/build/lib/extension/plugin-config.js.map +1 -0
- package/build/lib/grid-register.d.ts +10 -0
- package/build/lib/grid-register.d.ts.map +1 -0
- package/build/lib/grid-register.js +122 -144
- package/build/lib/grid-register.js.map +1 -0
- package/build/lib/logger.d.ts +3 -0
- package/build/lib/logger.d.ts.map +1 -0
- package/build/lib/logger.js +5 -17
- package/build/lib/logger.js.map +1 -0
- package/build/lib/logsink.d.ts +4 -0
- package/build/lib/logsink.d.ts.map +1 -0
- package/build/lib/logsink.js +190 -187
- package/build/lib/logsink.js.map +1 -0
- package/build/lib/main.d.ts +62 -0
- package/build/lib/main.d.ts.map +1 -0
- package/build/lib/main.js +339 -229
- package/build/lib/main.js.map +1 -0
- package/build/lib/schema/arg-spec.d.ts +143 -0
- package/build/lib/schema/arg-spec.d.ts.map +1 -0
- package/build/lib/schema/arg-spec.js +164 -0
- package/build/lib/schema/arg-spec.js.map +1 -0
- package/build/lib/schema/cli-args.d.ts +19 -0
- package/build/lib/schema/cli-args.d.ts.map +1 -0
- package/build/lib/schema/cli-args.js +217 -0
- package/build/lib/schema/cli-args.js.map +1 -0
- package/build/lib/schema/cli-transformers.d.ts +5 -0
- package/build/lib/schema/cli-transformers.d.ts.map +1 -0
- package/build/lib/schema/cli-transformers.js +124 -0
- package/build/lib/schema/cli-transformers.js.map +1 -0
- package/build/lib/schema/index.d.ts +3 -0
- package/build/lib/schema/index.d.ts.map +1 -0
- package/build/lib/schema/index.js +19 -0
- package/build/lib/schema/index.js.map +1 -0
- package/build/lib/schema/keywords.d.ts +24 -0
- package/build/lib/schema/keywords.d.ts.map +1 -0
- package/build/lib/schema/keywords.js +128 -0
- package/build/lib/schema/keywords.js.map +1 -0
- package/build/lib/schema/schema.d.ts +260 -0
- package/build/lib/schema/schema.d.ts.map +1 -0
- package/build/lib/schema/schema.js +640 -0
- package/build/lib/schema/schema.js.map +1 -0
- package/build/lib/utils.d.ts +266 -0
- package/build/lib/utils.d.ts.map +1 -0
- package/build/lib/utils.js +349 -273
- package/build/lib/utils.js.map +1 -0
- package/build/types/cli.d.ts +134 -0
- package/build/types/cli.d.ts.map +1 -0
- package/build/types/cli.js +3 -0
- package/build/types/cli.js.map +1 -0
- package/build/types/index.d.ts +15 -0
- package/build/types/index.d.ts.map +1 -0
- 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 +21 -0
- package/build/types/manifest/index.d.ts.map +1 -0
- package/build/types/manifest/index.js +42 -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/build/types/manifest/v4.d.ts +139 -0
- package/build/types/manifest/v4.d.ts.map +1 -0
- package/build/types/manifest/v4.js +3 -0
- package/build/types/manifest/v4.js.map +1 -0
- package/driver.d.ts +1 -0
- package/driver.js +14 -0
- package/index.js +11 -0
- package/lib/appium.js +558 -186
- package/lib/cli/args.js +277 -422
- package/lib/cli/driver-command.js +132 -24
- package/lib/cli/extension-command.js +751 -272
- package/lib/cli/extension.js +49 -18
- package/lib/cli/parser.js +263 -83
- package/lib/cli/plugin-command.js +122 -22
- package/lib/cli/utils.js +24 -10
- package/lib/config-file.js +220 -0
- package/lib/config.js +246 -111
- package/lib/constants.js +79 -0
- package/lib/extension/driver-config.js +247 -0
- package/lib/extension/extension-config.js +709 -0
- package/lib/extension/index.js +116 -0
- package/lib/extension/manifest-migrations.js +136 -0
- package/lib/extension/manifest.js +580 -0
- package/lib/extension/package-changed.js +64 -0
- package/lib/extension/plugin-config.js +112 -0
- package/lib/grid-register.js +49 -35
- package/lib/logger.js +1 -2
- package/lib/logsink.js +64 -38
- package/lib/main.js +318 -103
- package/lib/schema/arg-spec.js +229 -0
- package/lib/schema/cli-args.js +238 -0
- package/lib/schema/cli-transformers.js +119 -0
- package/lib/schema/index.js +2 -0
- package/lib/schema/keywords.js +136 -0
- package/lib/schema/schema.js +725 -0
- package/lib/utils.js +289 -167
- package/package.json +84 -84
- package/plugin.d.ts +1 -0
- package/plugin.js +13 -0
- package/scripts/autoinstall-extensions.js +243 -0
- package/support.d.ts +1 -0
- package/support.js +13 -0
- package/tsconfig.json +25 -0
- package/types/cli.ts +193 -0
- package/types/index.ts +20 -0
- package/types/manifest/README.md +30 -0
- package/types/manifest/base.ts +158 -0
- package/types/manifest/index.ts +28 -0
- package/types/manifest/v3.ts +161 -0
- package/types/manifest/v4.ts +161 -0
- package/CHANGELOG.md +0 -3515
- package/bin/ios-webkit-debug-proxy-launcher.js +0 -71
- package/build/lib/cli/npm.js +0 -208
- package/build/lib/cli/parser-helpers.js +0 -82
- package/build/lib/driver-config.js +0 -77
- package/build/lib/drivers.js +0 -96
- package/build/lib/extension-config.js +0 -253
- package/build/lib/plugin-config.js +0 -59
- package/build/lib/plugins.js +0 -14
- package/lib/cli/npm.js +0 -184
- package/lib/cli/parser-helpers.js +0 -79
- package/lib/driver-config.js +0 -46
- package/lib/drivers.js +0 -81
- package/lib/extension-config.js +0 -209
- package/lib/plugin-config.js +0 -34
- package/lib/plugins.js +0 -10
package/lib/cli/extension.js
CHANGED
|
@@ -1,43 +1,74 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
+
import {DRIVER_TYPE, PLUGIN_TYPE} from '../constants';
|
|
3
|
+
import {isExtensionCommandArgs} from '../utils';
|
|
4
|
+
import DriverCliCommand from './driver-command';
|
|
5
|
+
import PluginCliCommand from './plugin-command';
|
|
6
|
+
import {errAndQuit, JSON_SPACES} from './utils';
|
|
2
7
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
export const commandClasses = Object.freeze(
|
|
9
|
+
/** @type {const} */ ({
|
|
10
|
+
[DRIVER_TYPE]: DriverCliCommand,
|
|
11
|
+
[PLUGIN_TYPE]: PluginCliCommand,
|
|
12
|
+
})
|
|
13
|
+
);
|
|
9
14
|
|
|
10
15
|
/**
|
|
11
16
|
* Run a subcommand of the 'appium driver' type. Each subcommand has its own set of arguments which
|
|
12
17
|
* can be represented as a JS object.
|
|
13
18
|
*
|
|
14
|
-
* @
|
|
19
|
+
* @template {import('appium/types').CliExtensionCommand} Cmd
|
|
20
|
+
* @template {import('appium/types').CliExtensionSubcommand} SubCmd
|
|
21
|
+
* @param {import('appium/types').Args<Cmd, SubCmd>} args - JS object where the key is the parameter name (as defined in
|
|
15
22
|
* driver-parser.js)
|
|
23
|
+
* @param {import('../extension/extension-config').ExtensionConfig<Cmd>} config - Extension config object
|
|
16
24
|
*/
|
|
17
|
-
async function runExtensionCommand
|
|
25
|
+
async function runExtensionCommand(args, config) {
|
|
18
26
|
// TODO driver config file should be locked while any of these commands are
|
|
19
27
|
// running to prevent weird situations
|
|
20
28
|
let jsonResult = null;
|
|
21
|
-
const {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
const {extensionType: type} = config; // NOTE this is the same as `args.subcommand`
|
|
30
|
+
if (!isExtensionCommandArgs(args)) {
|
|
31
|
+
throw new TypeError(`Cannot call ${type} command without a subcommand like 'install'`);
|
|
32
|
+
}
|
|
33
|
+
let {json, suppressOutput} = args;
|
|
34
|
+
json = Boolean(json);
|
|
35
|
+
if (suppressOutput) {
|
|
36
|
+
json = true;
|
|
37
|
+
}
|
|
38
|
+
const CommandClass = /** @type {ExtCommand<Cmd>} */ (commandClasses[type]);
|
|
26
39
|
const cmd = new CommandClass({config, json});
|
|
27
40
|
try {
|
|
28
|
-
await config.read();
|
|
29
41
|
jsonResult = await cmd.execute(args);
|
|
30
42
|
} catch (err) {
|
|
43
|
+
// in the suppress output case, we are calling this function internally and should
|
|
44
|
+
// just throw instead of printing an error and ending the process
|
|
45
|
+
if (suppressOutput) {
|
|
46
|
+
throw err;
|
|
47
|
+
}
|
|
31
48
|
errAndQuit(json, err);
|
|
32
49
|
}
|
|
33
50
|
|
|
34
|
-
if (json) {
|
|
51
|
+
if (json && !suppressOutput) {
|
|
35
52
|
console.log(JSON.stringify(jsonResult, null, JSON_SPACES));
|
|
36
53
|
}
|
|
37
54
|
|
|
38
55
|
return jsonResult;
|
|
39
56
|
}
|
|
40
57
|
|
|
41
|
-
export {
|
|
42
|
-
|
|
43
|
-
|
|
58
|
+
export {runExtensionCommand};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @template {ExtensionType} ExtType
|
|
62
|
+
* @typedef {ExtType extends DriverType ? Class<DriverCliCommand> : ExtType extends PluginType ? Class<PluginCliCommand> : never} ExtCommand
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @typedef {import('@appium/types').ExtensionType} ExtensionType
|
|
67
|
+
* @typedef {import('@appium/types').DriverType} DriverType
|
|
68
|
+
* @typedef {import('@appium/types').PluginType} PluginType
|
|
69
|
+
*/
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @template T
|
|
73
|
+
* @typedef {import('@appium/types').Class<T>} Class
|
|
74
|
+
*/
|
package/lib/cli/parser.js
CHANGED
|
@@ -1,98 +1,278 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {fs} from '@appium/support';
|
|
2
|
+
import {ArgumentParser} from 'argparse';
|
|
2
3
|
import _ from 'lodash';
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import {DRIVER_TYPE, PLUGIN_TYPE, SERVER_SUBCOMMAND} from '../constants';
|
|
6
|
+
import {finalizeSchema, getArgSpec, hasArgSpec} from '../schema';
|
|
7
|
+
import {rootDir} from '../config';
|
|
8
|
+
import {getExtensionArgs, getServerArgs} from './args';
|
|
9
|
+
|
|
10
|
+
export const EXTRA_ARGS = 'extraArgs';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* If the parsed args do not contain any of these values, then we
|
|
14
|
+
* will automatially inject the `server` subcommand.
|
|
15
|
+
*/
|
|
16
|
+
const NON_SERVER_ARGS = Object.freeze(
|
|
17
|
+
new Set([DRIVER_TYPE, PLUGIN_TYPE, SERVER_SUBCOMMAND, '-h', '--help', '-v', '--version'])
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const version = fs.readPackageJsonFrom(rootDir).version;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A wrapper around `argparse`
|
|
24
|
+
*
|
|
25
|
+
* - Handles instantiation, configuration, and monkeypatching of an
|
|
26
|
+
* `ArgumentParser` instance for Appium server and its extensions
|
|
27
|
+
* - Handles error conditions, messages, and exit behavior
|
|
28
|
+
*/
|
|
29
|
+
class ArgParser {
|
|
30
|
+
/**
|
|
31
|
+
* @param {boolean} [debug] - If true, throw instead of exit on error.
|
|
32
|
+
*/
|
|
33
|
+
constructor(debug = false) {
|
|
34
|
+
const prog = process.argv[1] ? path.basename(process.argv[1]) : 'appium';
|
|
35
|
+
const parser = new ArgumentParser({
|
|
36
|
+
add_help: true,
|
|
37
|
+
description:
|
|
38
|
+
'A webdriver-compatible server that facilitates automation of web, mobile, and other types of apps across various platforms.',
|
|
39
|
+
prog,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
ArgParser._patchExit(parser);
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Program name (typically `appium`)
|
|
46
|
+
* @type {string}
|
|
47
|
+
*/
|
|
48
|
+
this.prog = prog;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* If `true`, throw an error on parse failure instead of printing help
|
|
52
|
+
* @type {boolean}
|
|
53
|
+
*/
|
|
54
|
+
this.debug = debug;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Wrapped `ArgumentParser` instance
|
|
58
|
+
* @type {ArgumentParser}
|
|
59
|
+
*/
|
|
60
|
+
this.parser = parser;
|
|
61
|
+
|
|
62
|
+
parser.add_argument('-v', '--version', {
|
|
63
|
+
action: 'version',
|
|
64
|
+
version,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const subParsers = parser.add_subparsers({dest: 'subcommand'});
|
|
68
|
+
|
|
69
|
+
// add the 'server' subcommand, and store the raw arguments on the parser
|
|
70
|
+
// object as a way for other parts of the code to work with the arguments
|
|
71
|
+
// conceptually rather than just through argparse
|
|
72
|
+
const serverArgs = ArgParser._addServerToParser(subParsers);
|
|
73
|
+
|
|
74
|
+
this.rawArgs = serverArgs;
|
|
75
|
+
|
|
76
|
+
// add the 'driver' and 'plugin' subcommands
|
|
77
|
+
ArgParser._addExtensionCommandsToParser(subParsers);
|
|
78
|
+
|
|
79
|
+
// backwards compatibility / drop-in wrapper
|
|
80
|
+
/**
|
|
81
|
+
* @type {ArgParser['parseArgs']}
|
|
82
|
+
*/
|
|
83
|
+
this.parse_args = this.parseArgs;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Parse arguments from the command line.
|
|
88
|
+
*
|
|
89
|
+
* If no subcommand is passed in, this method will inject the `server` subcommand.
|
|
90
|
+
*
|
|
91
|
+
* `ArgParser.prototype.parse_args` is an alias of this method.
|
|
92
|
+
* @template {import('appium/types').CliCommand} [Cmd=import('appium/types').CliCommandServer]
|
|
93
|
+
* @param {string[]} [args] - Array of arguments, ostensibly from `process.argv`. Gathers args from `process.argv` if not provided.
|
|
94
|
+
* @returns {import('appium/types').Args<Cmd>} - The parsed arguments
|
|
95
|
+
*/
|
|
96
|
+
parseArgs(args = process.argv.slice(2)) {
|
|
97
|
+
if (!NON_SERVER_ARGS.has(args[0])) {
|
|
98
|
+
args.unshift(SERVER_SUBCOMMAND);
|
|
36
99
|
}
|
|
37
|
-
return this._parseArgs(args, namespace);
|
|
38
|
-
}.bind(parser);
|
|
39
|
-
return parser;
|
|
40
|
-
}
|
|
41
100
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
101
|
+
try {
|
|
102
|
+
const parsed = this.parser.parse_known_args(args);
|
|
103
|
+
const [knownArgs, unknownArgs] = parsed;
|
|
104
|
+
if (
|
|
105
|
+
unknownArgs?.length &&
|
|
106
|
+
(knownArgs.driverCommand === 'run' || knownArgs.pluginCommand === 'run')
|
|
107
|
+
) {
|
|
108
|
+
return ArgParser._transformParsedArgs(knownArgs, unknownArgs);
|
|
109
|
+
} else if (unknownArgs?.length) {
|
|
110
|
+
throw new Error(`[ERROR] Unrecognized arguments: ${unknownArgs.join(' ')}`);
|
|
111
|
+
}
|
|
112
|
+
return ArgParser._transformParsedArgs(knownArgs);
|
|
113
|
+
} catch (err) {
|
|
114
|
+
if (this.debug) {
|
|
115
|
+
throw err;
|
|
116
|
+
}
|
|
117
|
+
// this isn't tested via unit tests (we use `debug: true`) so may escape coverage.
|
|
48
118
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
119
|
+
/* istanbul ignore next */
|
|
120
|
+
{
|
|
121
|
+
// eslint-disable-next-line no-console
|
|
122
|
+
console.error(); // need an extra space since argparse prints usage.
|
|
123
|
+
// eslint-disable-next-line no-console
|
|
124
|
+
console.error(err.message);
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
52
128
|
}
|
|
53
129
|
|
|
54
|
-
|
|
55
|
-
|
|
130
|
+
/**
|
|
131
|
+
* Given an object full of arguments as returned by `argparser.parse_args`,
|
|
132
|
+
* expand the ones for extensions into a nested object structure and rename
|
|
133
|
+
* keys to match the intended destination.
|
|
134
|
+
*
|
|
135
|
+
* E.g., `{'driver-foo-bar': baz}` becomes `{driver: {foo: {bar: 'baz'}}}`
|
|
136
|
+
* @param {object} args
|
|
137
|
+
* @param {string[]} [unknownArgs]
|
|
138
|
+
* @returns {object}
|
|
139
|
+
*/
|
|
140
|
+
static _transformParsedArgs(args, unknownArgs = []) {
|
|
141
|
+
const result = _.reduce(
|
|
142
|
+
args,
|
|
143
|
+
(unpacked, value, key) => {
|
|
144
|
+
if (!_.isUndefined(value) && hasArgSpec(key)) {
|
|
145
|
+
const {dest} = /** @type {import('../schema/arg-spec').ArgSpec} */ (getArgSpec(key));
|
|
146
|
+
_.set(unpacked, dest, value);
|
|
147
|
+
} else {
|
|
148
|
+
// this could be anything that _isn't_ a server arg
|
|
149
|
+
unpacked[key] = value;
|
|
150
|
+
}
|
|
151
|
+
return unpacked;
|
|
152
|
+
},
|
|
153
|
+
{}
|
|
154
|
+
);
|
|
155
|
+
result[EXTRA_ARGS] = unknownArgs;
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
56
158
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
159
|
+
/**
|
|
160
|
+
* Patches the `exit()` method of the parser to throw an error, so we can handle it manually.
|
|
161
|
+
* @param {ArgumentParser} parser
|
|
162
|
+
*/
|
|
163
|
+
static _patchExit(parser) {
|
|
164
|
+
parser.exit = (code, msg) => {
|
|
165
|
+
if (code) {
|
|
166
|
+
throw new Error(msg);
|
|
167
|
+
}
|
|
168
|
+
process.exit();
|
|
169
|
+
};
|
|
61
170
|
}
|
|
62
|
-
return defaults;
|
|
63
|
-
}
|
|
64
171
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
debug
|
|
172
|
+
/**
|
|
173
|
+
*
|
|
174
|
+
* @param {import('argparse').SubParser} subParser
|
|
175
|
+
* @returns {import('./args').ArgumentDefinitions}
|
|
176
|
+
*/
|
|
177
|
+
static _addServerToParser(subParser) {
|
|
178
|
+
const serverParser = subParser.add_parser('server', {
|
|
179
|
+
add_help: true,
|
|
180
|
+
help: 'Run an Appium server',
|
|
75
181
|
});
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
182
|
+
|
|
183
|
+
ArgParser._patchExit(serverParser);
|
|
184
|
+
|
|
185
|
+
const serverArgs = getServerArgs();
|
|
186
|
+
for (const [flagsOrNames, opts] of serverArgs) {
|
|
187
|
+
// TS doesn't like the spread operator here.
|
|
188
|
+
// @ts-ignore
|
|
189
|
+
serverParser.add_argument(...flagsOrNames, {...opts});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return serverArgs;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Adds extension sub-sub-commands to `driver`/`plugin` subcommands
|
|
197
|
+
* @param {import('argparse').SubParser} subParsers
|
|
198
|
+
*/
|
|
199
|
+
static _addExtensionCommandsToParser(subParsers) {
|
|
200
|
+
for (const type of /** @type {[DriverType, PluginType]} */ ([DRIVER_TYPE, PLUGIN_TYPE])) {
|
|
201
|
+
const extParser = subParsers.add_parser(type, {
|
|
202
|
+
add_help: true,
|
|
203
|
+
help: `Access the ${type} management CLI commands`,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
ArgParser._patchExit(extParser);
|
|
207
|
+
|
|
208
|
+
const extSubParsers = extParser.add_subparsers({
|
|
209
|
+
dest: `${type}Command`,
|
|
210
|
+
});
|
|
211
|
+
const extensionArgs = getExtensionArgs();
|
|
212
|
+
/**
|
|
213
|
+
* @type { {command: import('appium/types').CliExtensionSubcommand, args: import('./args').ArgumentDefinitions, help: string}[] }
|
|
214
|
+
*/
|
|
215
|
+
const parserSpecs = [
|
|
216
|
+
{
|
|
217
|
+
command: 'list',
|
|
218
|
+
args: extensionArgs[type].list,
|
|
219
|
+
help: `List available and installed ${type}s`,
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
command: 'install',
|
|
223
|
+
args: extensionArgs[type].install,
|
|
224
|
+
help: `Install a ${type}`,
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
command: 'uninstall',
|
|
228
|
+
args: extensionArgs[type].uninstall,
|
|
229
|
+
help: `Uninstall a ${type}`,
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
command: 'update',
|
|
233
|
+
args: extensionArgs[type].update,
|
|
234
|
+
help: `Update installed ${type}s to the latest version`,
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
command: 'run',
|
|
238
|
+
args: extensionArgs[type].run,
|
|
239
|
+
help:
|
|
240
|
+
`Run a script (defined inside the ${type}'s package.json under the ` +
|
|
241
|
+
`“scripts” field inside the “appium” field) from an installed ${type}`,
|
|
242
|
+
},
|
|
243
|
+
];
|
|
244
|
+
|
|
245
|
+
for (const {command, args, help} of parserSpecs) {
|
|
246
|
+
const parser = extSubParsers.add_parser(command, {help});
|
|
247
|
+
|
|
248
|
+
ArgParser._patchExit(parser);
|
|
249
|
+
|
|
250
|
+
for (const [flagsOrNames, opts] of args) {
|
|
251
|
+
// add_argument mutates params so make sure to send in copies instead
|
|
252
|
+
// @ts-ignore
|
|
253
|
+
parser.add_argument(...flagsOrNames, {...opts});
|
|
254
|
+
}
|
|
92
255
|
}
|
|
93
256
|
}
|
|
94
257
|
}
|
|
95
258
|
}
|
|
96
259
|
|
|
97
|
-
|
|
98
|
-
|
|
260
|
+
/**
|
|
261
|
+
* Creates a {@link ArgParser} instance; finalizes the config schema.
|
|
262
|
+
*
|
|
263
|
+
* @constructs ArgParser
|
|
264
|
+
* @param {boolean} [debug] - If `true`, throw instead of exit upon parsing error
|
|
265
|
+
* @returns {ArgParser}
|
|
266
|
+
*/
|
|
267
|
+
function getParser(debug) {
|
|
268
|
+
finalizeSchema();
|
|
269
|
+
|
|
270
|
+
return new ArgParser(debug);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export {getParser, ArgParser};
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* @typedef {import('@appium/types').DriverType} DriverType
|
|
277
|
+
* @typedef {import('@appium/types').PluginType} PluginType
|
|
278
|
+
*/
|
|
@@ -1,43 +1,143 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import { KNOWN_PLUGINS } from '../plugins';
|
|
2
|
+
import ExtensionCliCommand from './extension-command';
|
|
3
|
+
import {KNOWN_PLUGINS} from '../constants';
|
|
5
4
|
|
|
6
5
|
const REQ_PLUGIN_FIELDS = ['pluginName', 'mainClass'];
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
/**
|
|
8
|
+
* @extends {ExtensionCliCommand<PluginType>}
|
|
9
|
+
*/
|
|
10
|
+
export default class PluginCliCommand extends ExtensionCliCommand {
|
|
11
|
+
/**
|
|
12
|
+
*
|
|
13
|
+
* @param {import('./extension-command').ExtensionCommandOptions<PluginType>} opts
|
|
14
|
+
*/
|
|
15
|
+
constructor({config, json}) {
|
|
16
|
+
super({config, json});
|
|
12
17
|
this.knownExtensions = KNOWN_PLUGINS;
|
|
13
18
|
}
|
|
14
19
|
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Install a plugin
|
|
22
|
+
*
|
|
23
|
+
* @param {PluginInstallOpts} opts
|
|
24
|
+
* @returns {Promise<ExtRecord<PluginType>>}
|
|
25
|
+
*/
|
|
26
|
+
async install({plugin, installType, packageName}) {
|
|
27
|
+
return await super._install({
|
|
28
|
+
installSpec: plugin,
|
|
29
|
+
installType,
|
|
30
|
+
packageName,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Uninstall a plugin
|
|
36
|
+
*
|
|
37
|
+
* @param {PluginUninstallOpts} opts
|
|
38
|
+
* @returns {Promise<ExtRecord<PluginType>>}
|
|
39
|
+
*/
|
|
40
|
+
async uninstall({plugin}) {
|
|
41
|
+
return await super._uninstall({installSpec: plugin});
|
|
17
42
|
}
|
|
18
43
|
|
|
19
|
-
|
|
20
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Update a plugin
|
|
46
|
+
*
|
|
47
|
+
* @param {PluginUpdateOpts} opts
|
|
48
|
+
* @returns {Promise<import('./extension-command').ExtensionUpdateResult>}
|
|
49
|
+
*/
|
|
50
|
+
async update({plugin, unsafe}) {
|
|
51
|
+
return await super._update({installSpec: plugin, unsafe});
|
|
21
52
|
}
|
|
22
53
|
|
|
23
|
-
|
|
24
|
-
|
|
54
|
+
/**
|
|
55
|
+
*
|
|
56
|
+
* @param {PluginRunOptions} opts
|
|
57
|
+
* @returns {Promise<import('./extension-command').RunOutput>}
|
|
58
|
+
*/
|
|
59
|
+
async run({plugin, scriptName, extraArgs}) {
|
|
60
|
+
return await super._run({
|
|
61
|
+
installSpec: plugin,
|
|
62
|
+
scriptName,
|
|
63
|
+
extraArgs,
|
|
64
|
+
bufferOutput: this.isJsonOutput,
|
|
65
|
+
});
|
|
25
66
|
}
|
|
26
67
|
|
|
27
|
-
|
|
68
|
+
/**
|
|
69
|
+
*
|
|
70
|
+
* @param {import('./extension-command').ExtensionArgs} opts
|
|
71
|
+
* @returns {string}
|
|
72
|
+
*/
|
|
73
|
+
getPostInstallText({extName, extData}) {
|
|
28
74
|
return `Plugin ${extName}@${extData.version} successfully installed`.green;
|
|
29
75
|
}
|
|
30
76
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Validates fields in `appium` field of `pluginMetadata`
|
|
79
|
+
*
|
|
80
|
+
* For any `package.json` fields which a plugin requires, validate the type of
|
|
81
|
+
* those fields on the `package.json` data, throwing an error if anything is
|
|
82
|
+
* amiss.
|
|
83
|
+
* @param {import('appium/types').ExtMetadata<PluginType>} pluginMetadata
|
|
84
|
+
* @param {string} installSpec
|
|
85
|
+
* @returns {void}
|
|
86
|
+
*/
|
|
87
|
+
validateExtensionFields(pluginMetadata, installSpec) {
|
|
88
|
+
const missingFields = REQ_PLUGIN_FIELDS.reduce(
|
|
89
|
+
(acc, field) => (pluginMetadata[field] ? acc : [...acc, field]),
|
|
90
|
+
[]
|
|
91
|
+
);
|
|
35
92
|
|
|
36
93
|
if (!_.isEmpty(missingFields)) {
|
|
37
|
-
throw new Error(
|
|
38
|
-
|
|
94
|
+
throw new Error(
|
|
95
|
+
`Installed plugin "${installSpec}" did not expose correct fields for compability ` +
|
|
96
|
+
`with Appium. Missing fields: ${JSON.stringify(missingFields)}`
|
|
97
|
+
);
|
|
39
98
|
}
|
|
40
|
-
|
|
41
99
|
}
|
|
42
|
-
|
|
43
100
|
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @typedef {import('@appium/types').ExtensionType} ExtensionType
|
|
104
|
+
* @typedef {import('@appium/types').PluginType} PluginType
|
|
105
|
+
*/
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @template {ExtensionType} ExtType
|
|
109
|
+
* @typedef {import('appium/types').ExtRecord<ExtType>} ExtRecord
|
|
110
|
+
*/
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Options for {@linkcode PluginCliCommand.install}
|
|
114
|
+
* @typedef PluginInstallOpts
|
|
115
|
+
* @property {string} plugin - the name or spec of a plugin to install
|
|
116
|
+
* @property {InstallType} installType - how to install this plugin. One of the INSTALL_TYPES
|
|
117
|
+
* @property {string} [packageName] - for git/github installs, the plugin node package name
|
|
118
|
+
*/
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @typedef {import('appium/types').InstallType} InstallType
|
|
122
|
+
*/
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Options for {@linkcode PluginCliCommand.uninstall}
|
|
126
|
+
* @typedef PluginUninstallOpts
|
|
127
|
+
* @property {string} plugin - the name or spec of a plugin to uninstall
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Options for {@linkcode PluginCliCommand.update}
|
|
132
|
+
* @typedef PluginUpdateOpts
|
|
133
|
+
* @property {string} plugin - the name of the plugin to update
|
|
134
|
+
* @property {boolean} unsafe - if true, will perform unsafe updates past major revision boundaries
|
|
135
|
+
*/
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Options for {@linkcode PluginCliCommand.run}.
|
|
139
|
+
* @typedef PluginRunOptions
|
|
140
|
+
* @property {string} plugin - name of the plugin to run a script from
|
|
141
|
+
* @property {string} scriptName - name of the script to run
|
|
142
|
+
* @property {string[]} [extraArgs] - arguments to pass to the script
|
|
143
|
+
*/
|
package/lib/cli/utils.js
CHANGED
|
@@ -7,9 +7,9 @@ const JSON_SPACES = 4;
|
|
|
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
|
-
* @param {
|
|
10
|
+
* @param {any} msg - error message, object, Error instance, etc.
|
|
11
11
|
*/
|
|
12
|
-
function errAndQuit
|
|
12
|
+
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
|
|
29
|
+
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
|
|
39
|
+
async function spinWith(json, msg, fn) {
|
|
40
40
|
if (json) {
|
|
41
41
|
return await fn();
|
|
42
42
|
}
|
|
@@ -52,9 +52,23 @@ async function spinWith (json, msg, fn) {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
class RingBuffer {
|
|
56
|
+
constructor(size = 50) {
|
|
57
|
+
this.size = size;
|
|
58
|
+
this.buffer = [];
|
|
59
|
+
}
|
|
60
|
+
getBuff() {
|
|
61
|
+
return this.buffer;
|
|
62
|
+
}
|
|
63
|
+
dequeue() {
|
|
64
|
+
this.buffer.shift();
|
|
65
|
+
}
|
|
66
|
+
enqueue(item) {
|
|
67
|
+
if (this.buffer.length >= this.size) {
|
|
68
|
+
this.dequeue();
|
|
69
|
+
}
|
|
70
|
+
this.buffer.push(item);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export {errAndQuit, log, spinWith, JSON_SPACES, RingBuffer};
|