mirror of
https://github.com/appium/appium.git
synced 2026-01-25 03:38:52 -06:00
refactor: generalize DriverConfig into ExtensionConfig and make DriverConfig a special case of it
This commit is contained in:
@@ -1,11 +1,9 @@
|
||||
import { DEFAULT_BASE_PATH } from 'appium-base-driver';
|
||||
import { parseSecurityFeatures, parseDefaultCaps, parseInstallTypes } from './parser-helpers';
|
||||
import { INSTALL_TYPES, DEFAULT_APPIUM_HOME } from '../driver-config';
|
||||
import { INSTALL_TYPES, DEFAULT_APPIUM_HOME, DRIVER_TYPE, PLUGIN_TYPE } from '../extension-config';
|
||||
|
||||
const DRIVER_EXAMPLE = 'xcuitest';
|
||||
const PLUGIN_EXAMPLE = 'find_by_image';
|
||||
const DRIVER_TYPE = 'driver';
|
||||
const PLUGIN_TYPE = 'plugin';
|
||||
|
||||
// sharedArgs will be added to every subcommand
|
||||
const sharedArgs = [
|
||||
@@ -419,6 +417,4 @@ export {
|
||||
sharedArgs,
|
||||
serverArgs,
|
||||
extensionArgs,
|
||||
DRIVER_TYPE,
|
||||
PLUGIN_TYPE,
|
||||
};
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
import _ from 'lodash';
|
||||
import path from 'path';
|
||||
import { KNOWN_DRIVERS } from '../drivers';
|
||||
import DriverConfig, { INSTALL_TYPE_NPM, INSTALL_TYPE_GIT, INSTALL_TYPE_GITHUB,
|
||||
INSTALL_TYPE_LOCAL } from '../driver-config';
|
||||
import { DriverConfig, INSTALL_TYPE_NPM, INSTALL_TYPE_GIT, INSTALL_TYPE_GITHUB,
|
||||
INSTALL_TYPE_LOCAL } from '../extension-config';
|
||||
import NPM from './npm';
|
||||
import { errAndQuit, log, spinWith, JSON_SPACES } from './utils';
|
||||
import { util, fs } from 'appium-support';
|
||||
@@ -61,12 +61,12 @@ class DriverCommand {
|
||||
|
||||
async list ({showInstalled, showUpdates}) {
|
||||
const lsMsg = `Listing ${showInstalled ? 'installed' : 'available'} drivers`;
|
||||
const installedNames = Object.keys(this.config.installedDrivers);
|
||||
const installedNames = Object.keys(this.config.installedExtensions);
|
||||
const knownNames = Object.keys(KNOWN_DRIVERS);
|
||||
const drivers = [...installedNames, ...knownNames].reduce((acc, name) => {
|
||||
if (!acc[name]) {
|
||||
if (installedNames.includes(name)) {
|
||||
acc[name] = {...this.config.installedDrivers[name], installed: true};
|
||||
acc[name] = {...this.config.installedExtensions[name], installed: true};
|
||||
} else if (!showInstalled) {
|
||||
acc[name] = {pkgName: KNOWN_DRIVERS[name], installed: false};
|
||||
}
|
||||
@@ -200,14 +200,14 @@ class DriverCommand {
|
||||
|
||||
driverData.installType = installType;
|
||||
driverData.installSpec = installSpec;
|
||||
await this.config.addDriver(driverName, driverData);
|
||||
await this.config.addExtension(driverName, driverData);
|
||||
|
||||
// log info for the user
|
||||
log(this.isJsonOutput, `Driver ${driverName}@${driverData.version} successfully installed`.green);
|
||||
log(this.isJsonOutput, `- automationName: ${driverData.automationName.green}`);
|
||||
log(this.isJsonOutput, `- platformNames: ${JSON.stringify(driverData.platformNames).green}`);
|
||||
|
||||
return this.config.installedDrivers;
|
||||
return this.config.installedExtensions;
|
||||
}
|
||||
|
||||
async installViaNpm ({driver, pkgName, pkgVer}) {
|
||||
@@ -268,10 +268,10 @@ class DriverCommand {
|
||||
try {
|
||||
await fs.rimraf(this.config.getInstallPath(driver));
|
||||
} finally {
|
||||
await this.config.removeDriver(driver);
|
||||
await this.config.removeExtension(driver);
|
||||
}
|
||||
log(this.isJsonOutput, `Successfully uninstalled driver '${driver}'`.green);
|
||||
return this.config.installedDrivers;
|
||||
return this.config.installedExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -305,7 +305,7 @@ class DriverCommand {
|
||||
if (!shouldUpdateAll && !this.config.isInstalled(driver)) {
|
||||
throw new Error(`Driver '${driver}' was not installed, so can't be updated`);
|
||||
}
|
||||
const driversToUpdate = shouldUpdateAll ? Object.keys(this.config.installedDrivers) : [driver];
|
||||
const driversToUpdate = shouldUpdateAll ? Object.keys(this.config.installedExtensions) : [driver];
|
||||
|
||||
// 'errors' will have driver names as keys and error objects as values
|
||||
const errors = {};
|
||||
@@ -317,7 +317,7 @@ class DriverCommand {
|
||||
for (const d of driversToUpdate) {
|
||||
try {
|
||||
await spinWith(this.isJsonOutput, `Checking if driver '${d}' is updatable`, () => {
|
||||
if (this.config.installedDrivers[d].installType !== INSTALL_TYPE_NPM) {
|
||||
if (this.config.installedExtensions[d].installType !== INSTALL_TYPE_NPM) {
|
||||
throw new NotUpdatableError();
|
||||
}
|
||||
});
|
||||
@@ -382,7 +382,7 @@ class DriverCommand {
|
||||
// TODO decide how we want to handle beta versions?
|
||||
// this is a helper method, 'driver' is assumed to already be installed here, and of the npm
|
||||
// install type
|
||||
const {version, pkgName} = this.config.installedDrivers[driver];
|
||||
const {version, pkgName} = this.config.installedExtensions[driver];
|
||||
let unsafeUpdate = await this.npm.getLatestVersion(pkgName);
|
||||
let safeUpdate = await this.npm.getLatestSafeUpgradeVersion(pkgName, version);
|
||||
if (!util.compareVersions(unsafeUpdate, '>', version)) {
|
||||
@@ -409,9 +409,9 @@ class DriverCommand {
|
||||
* @param {string} version - version string identifier to update driver to
|
||||
*/
|
||||
async updateDriver (driver, version) {
|
||||
const {pkgName} = this.config.installedDrivers[driver];
|
||||
const {pkgName} = this.config.installedExtensions[driver];
|
||||
await this.installViaNpm({driver, pkgName, pkgVer: version});
|
||||
this.config.installedDrivers[driver].version = version;
|
||||
this.config.installedExtensions[driver].version = version;
|
||||
await this.config.write();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import fs from 'fs';
|
||||
import _ from 'lodash';
|
||||
import { INSTALL_TYPES } from '../driver-config';
|
||||
import { INSTALL_TYPES } from '../extension-config';
|
||||
|
||||
// serverArgs will be added to the `server` (default) subcommand
|
||||
function parseSecurityFeatures (features) {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import path from 'path';
|
||||
import _ from 'lodash';
|
||||
import { ArgumentParser } from 'argparse';
|
||||
import { sharedArgs, serverArgs, extensionArgs, DRIVER_TYPE, PLUGIN_TYPE } from './args';
|
||||
import { sharedArgs, serverArgs, extensionArgs } from './args';
|
||||
import { DRIVER_TYPE, PLUGIN_TYPE } from '../extension-config';
|
||||
import { rootDir } from '../utils';
|
||||
|
||||
function getParser (debug = false) {
|
||||
|
||||
@@ -57,9 +57,9 @@ function findMatchingDriver (config, {automationName, platformName}) {
|
||||
driverName,
|
||||
mainClass,
|
||||
version,
|
||||
} = getDriverBySupport(config.installedDrivers, automationName, platformName);
|
||||
} = getDriverBySupport(config.installedExtensions, automationName, platformName);
|
||||
log.info(`The '${driverName}' driver was installed and matched caps.`);
|
||||
log.info(`Will require it at ${config.getDriverRequirePath(driverName)}`);
|
||||
log.info(`Will require it at ${config.getExtensionRequirePath(driverName)}`);
|
||||
const driver = config.require(driverName);
|
||||
if (!driver) {
|
||||
throw new Error(`MainClass ${mainClass} did not result in a driver object`);
|
||||
|
||||
@@ -4,10 +4,12 @@ import { fs, mkdirp } from 'appium-support';
|
||||
import path from 'path';
|
||||
import YAML from 'yaml';
|
||||
|
||||
const DRIVER_TYPE = 'driver';
|
||||
const PLUGIN_TYPE = 'plugin';
|
||||
const DEFAULT_APPIUM_HOME = path.resolve(process.env.HOME, '.appium');
|
||||
|
||||
const CONFIG_FILE_NAME = 'drivers.yaml';
|
||||
const CONFIG_SCHEMA_REV = 1;
|
||||
const CONFIG_FILE_NAME = 'extensions.yaml';
|
||||
const CONFIG_SCHEMA_REV = 2;
|
||||
|
||||
const INSTALL_TYPE_NPM = 'npm';
|
||||
const INSTALL_TYPE_LOCAL = 'local';
|
||||
@@ -21,31 +23,44 @@ const INSTALL_TYPES = [
|
||||
];
|
||||
|
||||
|
||||
export default class DriverConfig {
|
||||
constructor (appiumHome, logFn = null) {
|
||||
export default class ExtensionConfig {
|
||||
constructor (appiumHome, extensionType, logFn = null) {
|
||||
if (logFn === null) {
|
||||
logFn = log.error.bind(log);
|
||||
}
|
||||
this.appiumHome = appiumHome;
|
||||
this.configFile = path.resolve(this.appiumHome, CONFIG_FILE_NAME);
|
||||
this.installedDrivers = {};
|
||||
this.installedExtensions = {};
|
||||
this.extensionType = extensionType;
|
||||
this.configKey = `${extensionType}s`;
|
||||
this.yamlData = {[`${DRIVER_TYPE}s`]: {}, [`${PLUGIN_TYPE}s`]: {}};
|
||||
this.log = logFn;
|
||||
}
|
||||
|
||||
validate () {
|
||||
throw new Error('This method must be implemented in a final class');
|
||||
}
|
||||
|
||||
applySchemaMigrations () {
|
||||
if (this.yamlData.schemaRev < 2 && _.isUndefined(this.yamlData[PLUGIN_TYPE])) {
|
||||
// at schema revision 2, we started including plugins as well as drivers in the file,
|
||||
// so make sure we at least have an empty section for it
|
||||
this.yamlData[PLUGIN_TYPE] = {};
|
||||
}
|
||||
}
|
||||
|
||||
async read () {
|
||||
await mkdirp(this.appiumHome); // ensure appium home exists
|
||||
try {
|
||||
const yamlData = YAML.parse(await fs.readFile(this.configFile, 'utf8'));
|
||||
// in the future if we need to do anything specific based on schema
|
||||
// revision, we can check it as follows
|
||||
// const schemaRev = yamlData.schemaRev;
|
||||
this.yamlData = YAML.parse(await fs.readFile(this.configFile, 'utf8'));
|
||||
this.applySchemaMigrations();
|
||||
|
||||
// set the list of drivers the user has installed
|
||||
this.installedDrivers = this.validate(yamlData.drivers);
|
||||
this.installedExtensions = this.validate(this.yamlData[this.configKey]);
|
||||
} catch (err) {
|
||||
if (await fs.exists(this.configFile)) {
|
||||
// if the file exists and we couldn't parse it, that's a problem
|
||||
throw new Error(`Appium had trouble loading the driver installation ` +
|
||||
throw new Error(`Appium had trouble loading the extension installation ` +
|
||||
`cache file (${this.configFile}). Ensure it exists and is ` +
|
||||
`readable. Specific error: ${err.message}`);
|
||||
}
|
||||
@@ -59,7 +74,70 @@ export default class DriverConfig {
|
||||
`(${this.appiumHome}). Please ensure it is writable.`);
|
||||
}
|
||||
}
|
||||
return this.installedDrivers;
|
||||
return this.installedExtensions;
|
||||
}
|
||||
|
||||
|
||||
async write () {
|
||||
const newYamlData = {
|
||||
...this.yamlData,
|
||||
schemaRev: CONFIG_SCHEMA_REV,
|
||||
[this.configKey]: this.installedExtensions
|
||||
};
|
||||
await fs.writeFile(this.configFile, YAML.stringify(newYamlData), 'utf8');
|
||||
}
|
||||
|
||||
async addExtension (extName, extData) {
|
||||
this.installedExtensions[extName] = extData;
|
||||
await this.write();
|
||||
}
|
||||
|
||||
async removeExtension (extName) {
|
||||
delete this.installedExtensions[extName];
|
||||
await this.write();
|
||||
}
|
||||
|
||||
print () {
|
||||
const extNames = Object.keys(this.installedExtensions);
|
||||
if (_.isEmpty(extNames)) {
|
||||
log.info(`No ${this.configKey} have been installed. Use the "appium ${this.extensionType}" ` +
|
||||
'command to install the one(s) you want to use.');
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(`Available ${this.configKey}:`);
|
||||
for (const [extName, extData] of _.toPairs(this.installedExtensions)) {
|
||||
log.info(` - ${this.extensionDesc(extName, extData)}`);
|
||||
}
|
||||
}
|
||||
|
||||
extensionDesc () {
|
||||
throw new Error('This must be implemented in a final class');
|
||||
}
|
||||
|
||||
getExtensionRequirePath (extName) {
|
||||
const {pkgName, installPath} = this.installedExtensions[extName];
|
||||
return path.resolve(this.appiumHome, installPath, 'node_modules', pkgName);
|
||||
}
|
||||
|
||||
getInstallPath (extName) {
|
||||
const {installPath} = this.installedExtensions[extName];
|
||||
return path.resolve(this.appiumHome, installPath);
|
||||
}
|
||||
|
||||
require (extName) {
|
||||
const {mainClass} = this.installedExtensions[extName];
|
||||
return require(this.getExtensionRequirePath(extName))[mainClass];
|
||||
}
|
||||
|
||||
isInstalled (extName) {
|
||||
return _.includes(Object.keys(this.installedExtensions), extName);
|
||||
}
|
||||
}
|
||||
|
||||
class DriverConfig extends ExtensionConfig {
|
||||
constructor (appiumHome, logFn = null) {
|
||||
super(appiumHome, DRIVER_TYPE, logFn);
|
||||
}
|
||||
|
||||
validate (drivers) {
|
||||
@@ -134,7 +212,7 @@ export default class DriverConfig {
|
||||
}
|
||||
// remove this driver from the list since it's not valid
|
||||
delete drivers[driverName];
|
||||
problemSummaries.push(`Driver ${driverName} had errors and will not ` +
|
||||
problemSummaries.push(`Extension ${driverName} had errors and will not ` +
|
||||
`be available. Errors:`);
|
||||
for (const problem of problems) {
|
||||
problemSummaries.push(` - ${problem.err} (Actual value: ` +
|
||||
@@ -153,56 +231,19 @@ export default class DriverConfig {
|
||||
return drivers;
|
||||
}
|
||||
|
||||
async write () {
|
||||
const yamlData = {schemaRev: CONFIG_SCHEMA_REV, drivers: this.installedDrivers};
|
||||
await fs.writeFile(this.configFile, YAML.stringify(yamlData), 'utf8');
|
||||
extensionDesc (driverName, {version, automationName}) {
|
||||
return `${driverName}@${version} (automationName '${automationName}')`;
|
||||
}
|
||||
}
|
||||
|
||||
async addDriver (driverName, driverData) {
|
||||
this.installedDrivers[driverName] = driverData;
|
||||
await this.write();
|
||||
}
|
||||
|
||||
async removeDriver (driverName) {
|
||||
delete this.installedDrivers[driverName];
|
||||
await this.write();
|
||||
}
|
||||
|
||||
print () {
|
||||
const driverNames = Object.keys(this.installedDrivers);
|
||||
if (_.isEmpty(driverNames)) {
|
||||
log.info('No drivers have been installed. Use the "appium driver" ' +
|
||||
'command to install the one(s) you want to use.');
|
||||
return;
|
||||
}
|
||||
|
||||
log.info('Available drivers:');
|
||||
for (const [driverName, {version, automationName}] of _.toPairs(this.installedDrivers)) {
|
||||
log.info(` - ${driverName}@${version} (automationName '${automationName}')`);
|
||||
}
|
||||
}
|
||||
|
||||
getDriverRequirePath (driverName) {
|
||||
const {pkgName, installPath} = this.installedDrivers[driverName];
|
||||
return path.resolve(this.appiumHome, installPath, 'node_modules', pkgName);
|
||||
}
|
||||
|
||||
getInstallPath (driverName) {
|
||||
const {installPath} = this.installedDrivers[driverName];
|
||||
return path.resolve(this.appiumHome, installPath);
|
||||
}
|
||||
|
||||
require (driverName) {
|
||||
const {mainClass} = this.installedDrivers[driverName];
|
||||
return require(this.getDriverRequirePath(driverName))[mainClass];
|
||||
}
|
||||
|
||||
isInstalled (driverName) {
|
||||
return _.includes(Object.keys(this.installedDrivers), driverName);
|
||||
class PluginConfig extends ExtensionConfig {
|
||||
constructor (appiumHome, logFn = null) {
|
||||
super(appiumHome, PLUGIN_TYPE, logFn);
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
INSTALL_TYPE_NPM, INSTALL_TYPE_GIT, INSTALL_TYPE_LOCAL, INSTALL_TYPE_GITHUB,
|
||||
INSTALL_TYPES, DEFAULT_APPIUM_HOME
|
||||
INSTALL_TYPES, DEFAULT_APPIUM_HOME, DriverConfig, PluginConfig, DRIVER_TYPE,
|
||||
PLUGIN_TYPE,
|
||||
};
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
warnNodeDeprecations, validateTmpDir, getNonDefaultArgs,
|
||||
getGitRev, APPIUM_VER
|
||||
} from './config';
|
||||
import DriverConfig from './driver-config';
|
||||
import { DriverConfig } from './extension-config';
|
||||
import { runDriverCommand } from './cli/driver';
|
||||
import { AppiumDriver } from './appium';
|
||||
import registerNode from './grid-register';
|
||||
@@ -128,8 +128,9 @@ async function main (args = null) {
|
||||
}
|
||||
|
||||
let appiumDriver = new AppiumDriver(args);
|
||||
appiumDriver.driverConfig = new DriverConfig(args.appiumHome);
|
||||
await preflightChecks({parser, args, driverConfig: appiumDriver.driverConfig, throwInsteadOfExit});
|
||||
const driverConfig = new DriverConfig(args.appiumHome);
|
||||
appiumDriver.driverConfig = driverConfig;
|
||||
await preflightChecks({parser, args, driverConfig, throwInsteadOfExit});
|
||||
await logStartupInfo(parser, args);
|
||||
let routeConfiguringFunction = makeRouter(appiumDriver);
|
||||
let server = await baseServer({
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import chai from 'chai';
|
||||
import chaiAsPromised from 'chai-as-promised';
|
||||
import DriverConfig, { DEFAULT_APPIUM_HOME } from '../lib/driver-config';
|
||||
import { DriverConfig, DEFAULT_APPIUM_HOME } from '../lib/extension-config';
|
||||
import { DriverCommand } from '../lib/cli/driver';
|
||||
import sinon from 'sinon';
|
||||
|
||||
@@ -13,7 +13,7 @@ describe('DriverCommand', function () {
|
||||
const config = new DriverConfig(DEFAULT_APPIUM_HOME);
|
||||
const driver = 'fake';
|
||||
const pkgName = 'appium-fake-driver';
|
||||
config.installedDrivers = {[driver]: {version: '1.0.0', pkgName}};
|
||||
config.installedExtensions = {[driver]: {version: '1.0.0', pkgName}};
|
||||
const dc = new DriverCommand({config, json: true});
|
||||
|
||||
describe('#checkForDriverUpdate', function () {
|
||||
|
||||
@@ -7,7 +7,7 @@ import chaiAsPromised from 'chai-as-promised';
|
||||
import wd from 'wd';
|
||||
import axios from 'axios';
|
||||
import { main as appiumServer } from '../lib/main';
|
||||
import { DEFAULT_APPIUM_HOME, INSTALL_TYPE_NPM } from '../lib/driver-config';
|
||||
import { DEFAULT_APPIUM_HOME, INSTALL_TYPE_NPM } from '../lib/extension-config';
|
||||
import { TEST_FAKE_APP, TEST_HOST, TEST_PORT } from './helpers';
|
||||
import { BaseDriver } from 'appium-base-driver';
|
||||
import { FakeDriver } from 'appium-fake-driver';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// transpile:mocha
|
||||
|
||||
import { getParser } from '../lib/cli/parser';
|
||||
import { INSTALL_TYPES, DEFAULT_APPIUM_HOME } from '../lib/driver-config';
|
||||
import { INSTALL_TYPES, DEFAULT_APPIUM_HOME } from '../lib/extension-config';
|
||||
import chai from 'chai';
|
||||
|
||||
const should = chai.should();
|
||||
|
||||
Reference in New Issue
Block a user