fix: install each driver into its own subdirectory
to ensure that npm install doesn't do weird things with different subdependencies of each
MODIFY
lib/driver-cli.js
lib/driver-cli.js
import _ from 'lodash';
+import path from 'path';
import { KNOWN_DRIVERS, validateDriversYaml, writeInstalledDriver,
INSTALL_TYPE_LOCAL, INSTALL_TYPE_NPM, INSTALL_TYPE_GIT,
INSTALL_TYPE_GITHUB } from './drivers';
@@ -127,6 +128,7 @@ async function install ({appiumHome, json, driver, installType}) {
await linkPackage(appiumHome, installSpec))
);
driverData = getDriverFields(pkgJsonData);
+ driverData.installPath = driverData.pkgName;
} else if (installType === INSTALL_TYPE_GITHUB) {
if (installSpec.split('/').length !== 2) {
throw new Error(`Github driver spec ${installSpec} appeared to be invalid; ` +
@@ -191,17 +193,21 @@ async function install ({appiumHome, json, driver, installType}) {
}
async function installViaNpm ({appiumHome, json, driver, pkgName, pkgVer}) {
+ let installPath = pkgName;
if (!pkgName) {
pkgName = driver;
+ installPath = path.posix.basename(pkgName);
}
const npmSpec = `${pkgName}${pkgVer ? '@' + pkgVer : ''}`;
const specMsg = npmSpec === driver ? '' : ` using NPM install spec '${npmSpec}'`;
const msg = `Installing '${driver}'${specMsg}`;
try {
const pkgJsonData = await spinWith(json, msg, async () => (
- await installPackage(appiumHome, pkgName, pkgVer)
+ await installPackage(path.resolve(appiumHome, installPath), pkgName, pkgVer)
));
- return getDriverFields(pkgJsonData);
+ const driverData = getDriverFields(pkgJsonData);
+ driverData.installPath = installPath;
+ return driverData;
} catch (err) {
throw new Error(`Encountered an error when installing package: ${err.message}`);
}

MODIFY
lib/drivers.js
lib/drivers.js
@@ -66,6 +66,7 @@ async function validateDriversYaml (appiumHome, logFn = log.error) {
pkgName,
installSpec,
installType,
+ installPath,
mainClass
}] of _.toPairs(INSTALLED_DRIVERS)) {
const p = foundProblems[driverName] = []; // just a little alias for convenience
@@ -111,6 +112,10 @@ async function validateDriversYaml (appiumHome, logFn = log.error) {
p.push({err: 'Missing or incorrect install type', val: installType});
}
+ if (!_.isString(installPath)) {
+ p.push({err: 'Missing or incorrect installation path', val: installPath});
+ }
+
if (!_.isString(mainClass)) {
p.push({err: 'Missing or incorrect driver class name', val: mainClass});
}
@@ -198,9 +203,16 @@ function findMatchingDriver (appiumHome, {automationName, platformName}) {
`'${automationName}' and platformName '${platformName}'`);
try {
- const {driverName, mainClass, pkgName, version} = getDriverBySupport(automationName, platformName);
+ const {
+ driverName,
+ mainClass,
+ pkgName,
+ version,
+ installPath
+ } = getDriverBySupport(automationName, platformName);
log.info(`The '${driverName}' driver was installed and matched caps.`);
- const pkgPath = path.resolve(appiumHome, 'node_modules', pkgName);
+ const pkgPath = path.resolve(appiumHome, installPath, 'node_modules', pkgName);
+ log.info(`Will require it at ${pkgPath}`);
const driver = require(pkgPath)[mainClass];
if (!driver) {
throw new Error(`MainClass ${mainClass} did not result in a driver object`);

MODIFY
lib/npm.js
lib/npm.js
import _ from 'lodash';
import path from 'path';
import { exec } from 'teen_process';
-import { util } from 'appium-support';
+import { mkdirp, util } from 'appium-support';
const INSTALL_LOCKFILE = '.appium.install.lock';
const LINK_LOCKFILE = '.appium.link.lock';
async function npmExec (cmd, args, opts, execOpts = {}) {
- const { appiumHome, json, lockFile } = opts;
- if (!appiumHome) {
- throw new Error('appiumHome was not provided to npmExec');
+ const { cwd, json, lockFile } = opts;
+ if (!cwd) {
+ throw new Error('cwd was not provided to npmExec');
}
- execOpts.cwd = appiumHome;
+ // ensure the directory we want to install to exists
+ await mkdirp(cwd);
+ execOpts.cwd = cwd;
args.unshift(cmd);
if (json) {
@@ -19,7 +21,7 @@ async function npmExec (cmd, args, opts, execOpts = {}) {
}
let runner = async () => await exec('npm', args, execOpts);
if (lockFile) {
- const acquireLock = util.getLockFileGuard(path.resolve(appiumHome, lockFile));
+ const acquireLock = util.getLockFileGuard(path.resolve(cwd, lockFile));
const _runner = runner;
runner = async () => await acquireLock(_runner);
}
@@ -41,17 +43,17 @@ async function npmExec (cmd, args, opts, execOpts = {}) {
async function getLatestVersion (appiumHome, pkg) {
return (await npmExec('view', [pkg, 'dist-tags'], {
json: true,
- appiumHome
+ cwd: appiumHome
})).json.latest;
}
-async function installPackage (appiumHome, pkg, ver) {
+async function installPackage (pkgDir, pkg, ver) {
const res = await npmExec('install', [
'--no-save',
'--no-package-lock',
ver ? `${pkg}@${ver}` : pkg
], {
- appiumHome,
+ cwd: pkgDir,
json: true,
lockFile: INSTALL_LOCKFILE
});
@@ -60,7 +62,7 @@ async function installPackage (appiumHome, pkg, ver) {
// package.json, but if we're installing from github, we don't know that yet.
// as a first pass, assume the package name is the last component of the
// package which we're sending to npm install.
- let pkgName = path.basename(pkg);
+ let pkgName = path.posix.basename(pkg);
if (res.json) {
// we parsed a valid json response, so if we got an error here, return that
@@ -80,7 +82,7 @@ async function installPackage (appiumHome, pkg, ver) {
// Now read package data from the installed package to return, and make sure
// everything got installed ok
- const pkgJson = path.resolve(appiumHome, 'node_modules', pkgName, 'package.json');
+ const pkgJson = path.resolve(pkgDir, 'node_modules', pkgName, 'package.json');
try {
return require(pkgJson);
} catch {
@@ -101,14 +103,15 @@ async function linkPackage (appiumHome, pkgPath) {
`provided: ${pkgPath}`);
}
- const res = await npmExec('link', [pkgPath], {appiumHome, lockFile: LINK_LOCKFILE});
+ const pkgHome = path.resolve(appiumHome, pkgName);
+ const res = await npmExec('link', [pkgPath], {cwd: pkgHome, lockFile: LINK_LOCKFILE});
if (res.json && res.json.error) {
throw new Error(res.json.error);
}
// now ensure it was linked to the correct place
try {
- return require(path.resolve(appiumHome, 'node_modules', pkgName, 'package.json'));
+ return require(path.resolve(pkgHome, 'node_modules', pkgName, 'package.json'));
} catch {
throw new Error('The package was not linked correctly; its package.json ' +
'did not exist or was unreadable');

MODIFY
package.json
package.json
],
"dependencies": {
"@babel/runtime": "^7.6.0",
- "appium-android-driver": "^4.20.0",
"appium-base-driver": "^6.0.1",
- "appium-espresso-driver": "^1.0.0",
- "appium-fake-driver": "^0.x",
- "appium-flutter-driver": "^0",
- "appium-ios-driver": "4.x",
- "appium-mac-driver": "1.x",
"appium-support": "2.x",
- "appium-tizen-driver": "^1.1.1-beta.4",
- "appium-uiautomator2-driver": "^1.37.1",
- "appium-windows-driver": "1.x",
- "appium-xcuitest-driver": "^3.22.0",
- "appium-youiengine-driver": "^1.2.0",
"argparse": "^1.0.10",
"async-lock": "^1.0.0",
"asyncbox": "2.x",

fix: install each driver into its own subdirectory
to ensure that npm install doesn't do weird things with different subdependencies of each