1 | #!/usr/bin/env node
|
2 |
|
3 | const debug = require('debug')('selenium-standalone:cli');
|
4 |
|
5 | const minimist = require('minimist');
|
6 | const which = require('which');
|
7 | const merge = require('lodash.merge');
|
8 | const mapValues = require('lodash.mapvalues');
|
9 | const path = require('path');
|
10 |
|
11 | const selenium = require('../');
|
12 | const defaultConfig = require('../lib/default-config');
|
13 |
|
14 | const actions = {
|
15 | start: function (options) {
|
16 | const killEvents = ['exit', 'SIGTERM', 'SIGINT'];
|
17 |
|
18 | selenium.start(options, started);
|
19 |
|
20 | function started(err, cp) {
|
21 | if (err) {
|
22 | if (cp) {
|
23 | cp.kill('SIGINT');
|
24 | }
|
25 | throw err;
|
26 | }
|
27 |
|
28 | console.log('Selenium started');
|
29 |
|
30 | killEvents.forEach(register);
|
31 |
|
32 | function register(evName) {
|
33 | process.on(evName, kill);
|
34 | }
|
35 |
|
36 | function unregister(evName) {
|
37 | process.removeListener(evName, kill);
|
38 | }
|
39 |
|
40 | function kill() {
|
41 | killEvents.forEach(unregister);
|
42 | cp.kill('SIGTERM');
|
43 | }
|
44 | }
|
45 | },
|
46 | install: function (options) {
|
47 | const ProgressBar = require('progress');
|
48 | let bar;
|
49 | let firstProgress = true;
|
50 |
|
51 | // eslint-disable-next-line no-param-reassign
|
52 | options.progressCb = options.silent ? null : progressCb;
|
53 |
|
54 | selenium.install(options, installed);
|
55 |
|
56 | function installed(err) {
|
57 | if (err) {
|
58 | throw err;
|
59 | }
|
60 | }
|
61 |
|
62 | function progressCb(total, progress, chunk, url, reset) {
|
63 | if (firstProgress) {
|
64 | console.log('');
|
65 | firstProgress = false;
|
66 | }
|
67 |
|
68 | if (reset || !bar) {
|
69 | bar = new ProgressBar('[:bar] :percent ' + url, {
|
70 | curr: progress,
|
71 | total: total,
|
72 | complete: '=',
|
73 | incomplete: ' ',
|
74 | width: 20,
|
75 | });
|
76 | }
|
77 |
|
78 | bar.tick(chunk);
|
79 | }
|
80 | },
|
81 | };
|
82 |
|
83 | function parseCommandAndOptions(javaPath) {
|
84 | const argv = minimist(process.argv.slice(2), {
|
85 | string: [
|
86 | 'version',
|
87 | 'drivers.chrome.version',
|
88 | 'drivers.ie.version',
|
89 | 'drivers.firefox.version',
|
90 | 'drivers.edge.version',
|
91 | ],
|
92 | });
|
93 |
|
94 | const action = argv._[0];
|
95 |
|
96 | if (!action) {
|
97 | throw new Error('No action provided');
|
98 | }
|
99 | if (action !== 'install' && action !== 'start') {
|
100 | throw new Error('Invalid action "' + action + ' (Valid actions are [' + Object.keys(actions).join(', ') + '])');
|
101 | }
|
102 |
|
103 | // everything after `selenium-standalone install [options] --` will be in argv._
|
104 | const seleniumArgs = argv._.slice(1);
|
105 |
|
106 | // build a new map removing `_` and --config from argv
|
107 | let options = Object.keys(argv).reduce((acc, cur) => {
|
108 | if (cur !== '_' && cur !== 'config') {
|
109 | acc[cur] = argv[cur];
|
110 | }
|
111 |
|
112 | return acc;
|
113 | }, {});
|
114 |
|
115 | // If a config file was specified, load it
|
116 | let configFromFile = {};
|
117 |
|
118 | if (argv.config) {
|
119 | try {
|
120 | configFromFile = require(path.resolve(process.cwd(), argv.config));
|
121 | if (typeof configFromFile !== 'object') {
|
122 | throw new Error('Config file does not exports an object');
|
123 | }
|
124 | } catch (err) {
|
125 | throw new Error('Error parsing config file : ' + (err.message || err));
|
126 | }
|
127 | }
|
128 |
|
129 | // Merge default options, options from config file then command line options
|
130 | options = merge({}, defaultConfig, configFromFile, options);
|
131 |
|
132 | // Ignore extra default drivers if specified in config file
|
133 | if (configFromFile.drivers && options.ignoreExtraDrivers) {
|
134 | options.drivers = mapValues(configFromFile.drivers, (config, name) => {
|
135 | return merge({}, defaultConfig.drivers[name], config);
|
136 | });
|
137 | }
|
138 |
|
139 | if (seleniumArgs.length) {
|
140 | options.seleniumArgs = seleniumArgs;
|
141 | } else if (!Array.isArray(options.seleniumArgs)) {
|
142 | options.seleniumArgs = [];
|
143 | }
|
144 | options.spawnOptions = {
|
145 | stdio: 'inherit',
|
146 | };
|
147 |
|
148 | options.logger = options.silent ? null : console.log;
|
149 | options.javaPath = javaPath;
|
150 |
|
151 | return [action, options];
|
152 | }
|
153 |
|
154 | // Export the command line parsing function for tests.
|
155 | module.exports = parseCommandAndOptions;
|
156 |
|
157 | if (!process.env || !process.env.NODE_ENV || process.env.NODE_ENV !== 'test-cli-parameters') {
|
158 | which('java', function javaFound(errWhich, javaPath) {
|
159 | debug('Started via CLI with: ', process.argv);
|
160 |
|
161 | let params;
|
162 |
|
163 | try {
|
164 | if (errWhich) {
|
165 | throw errWhich;
|
166 | }
|
167 | params = parseCommandAndOptions(javaPath);
|
168 | } catch (err) {
|
169 | process.stderr.write((err.message || err) + '\n');
|
170 | process.stderr.write('Usage: selenium-standalone action [options]\n');
|
171 | process.exit(255);
|
172 | }
|
173 | actions[params[0]](params[1]);
|
174 | });
|
175 | }
|