mirror of
https://github.com/apache/cordova-android.git
synced 2026-05-11 00:00:05 +08:00
refactor: unify target resolution for devices & emulators (#1101)
* refactor: unify target resolution for devices & emulators * fix: use unified target methods in platform-centric bins
This commit is contained in:
committed by
GitHub
parent
c774bf3311
commit
c04ea9b1c0
Vendored
-48
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var build = require('./build');
|
||||
var Adb = require('./Adb');
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
|
||||
/**
|
||||
* Returns a promise for the list of the device ID's found
|
||||
*/
|
||||
module.exports.list = async () => {
|
||||
return (await Adb.devices())
|
||||
.filter(id => !id.startsWith('emulator-'));
|
||||
};
|
||||
|
||||
module.exports.resolveTarget = function (target) {
|
||||
return this.list().then(function (device_list) {
|
||||
if (!device_list || !device_list.length) {
|
||||
return Promise.reject(new CordovaError('Failed to deploy to device, no devices found.'));
|
||||
}
|
||||
// default device
|
||||
target = target || device_list[0];
|
||||
|
||||
if (device_list.indexOf(target) < 0) {
|
||||
return Promise.reject(new CordovaError('ERROR: Unable to find target \'' + target + '\'.'));
|
||||
}
|
||||
|
||||
return build.detectArchitecture(target).then(function (arch) {
|
||||
return { target: target, arch: arch, isEmulator: false };
|
||||
});
|
||||
});
|
||||
};
|
||||
-19
@@ -20,7 +20,6 @@
|
||||
const execa = require('execa');
|
||||
const fs = require('fs-extra');
|
||||
var android_versions = require('android-versions');
|
||||
var build = require('./build');
|
||||
var path = require('path');
|
||||
var Adb = require('./Adb');
|
||||
var events = require('cordova-common').events;
|
||||
@@ -349,21 +348,3 @@ module.exports.wait_for_boot = function (emulator_id, time_remaining) {
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.resolveTarget = function (target) {
|
||||
return this.list_started().then(function (emulator_list) {
|
||||
if (emulator_list.length < 1) {
|
||||
return Promise.reject(new CordovaError('No running Android emulators found, please start an emulator before deploying your project.'));
|
||||
}
|
||||
|
||||
// default emulator
|
||||
target = target || emulator_list[0];
|
||||
if (emulator_list.indexOf(target) < 0) {
|
||||
return Promise.reject(new CordovaError('Unable to find target \'' + target + '\'. Failed to deploy to emulator.'));
|
||||
}
|
||||
|
||||
return build.detectArchitecture(target).then(function (arch) {
|
||||
return { target: target, arch: arch, isEmulator: true };
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -19,21 +19,21 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
const { install } = require('./target');
|
||||
var device = require('./device');
|
||||
const { resolve, install } = require('./target');
|
||||
|
||||
var args = process.argv;
|
||||
const targetSpec = { type: 'device' };
|
||||
|
||||
if (args.length > 2) {
|
||||
var install_target;
|
||||
if (args[2].substring(0, 9) === '--target=') {
|
||||
install_target = args[2].substring(9, args[2].length);
|
||||
targetSpec.id = args[2].substring(9, args[2].length);
|
||||
} else {
|
||||
console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
|
||||
process.exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
device.resolveTarget(install_target).then(install).catch(err => {
|
||||
resolve(targetSpec).then(install).catch(err => {
|
||||
console.error('ERROR: ' + err);
|
||||
process.exit(2);
|
||||
});
|
||||
|
||||
@@ -19,21 +19,21 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
const { install } = require('./target');
|
||||
var emulator = require('./emulator');
|
||||
var args = process.argv;
|
||||
const { resolve, install } = require('./target');
|
||||
|
||||
var args = process.argv;
|
||||
const targetSpec = { type: 'emulator' };
|
||||
|
||||
var install_target;
|
||||
if (args.length > 2) {
|
||||
if (args[2].substring(0, 9) === '--target=') {
|
||||
install_target = args[2].substring(9, args[2].length);
|
||||
targetSpec.id = args[2].substring(9, args[2].length);
|
||||
} else {
|
||||
console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
|
||||
process.exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
emulator.resolveTarget(install_target).then(install).catch(err => {
|
||||
resolve(targetSpec).then(install).catch(err => {
|
||||
console.error('ERROR: ' + err);
|
||||
process.exit(2);
|
||||
});
|
||||
|
||||
@@ -19,14 +19,16 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var devices = require('./device');
|
||||
const { list } = require('./target');
|
||||
|
||||
// Usage support for when args are given
|
||||
require('./check_reqs').check_android().then(function () {
|
||||
devices.list().then(function (device_list) {
|
||||
device_list && device_list.forEach(function (dev) {
|
||||
console.log(dev);
|
||||
});
|
||||
list().then(targets => {
|
||||
const deviceIds = targets
|
||||
.filter(({ type }) => type === 'device')
|
||||
.map(({ id }) => id);
|
||||
|
||||
console.log(deviceIds.join('\n'));
|
||||
}, function (err) {
|
||||
console.error('ERROR: ' + err);
|
||||
process.exit(2);
|
||||
|
||||
Vendored
+21
-57
@@ -19,22 +19,30 @@
|
||||
|
||||
var path = require('path');
|
||||
var emulator = require('./emulator');
|
||||
var device = require('./device');
|
||||
const target = require('./target');
|
||||
var PackageType = require('./PackageType');
|
||||
const { CordovaError, events } = require('cordova-common');
|
||||
const { events } = require('cordova-common');
|
||||
|
||||
function getInstallTarget (runOptions) {
|
||||
var install_target;
|
||||
/**
|
||||
* Builds a target spec from a runOptions object
|
||||
*
|
||||
* @param {{target?: string, device?: boolean, emulator?: boolean}} runOptions
|
||||
* @return {target.TargetSpec}
|
||||
*/
|
||||
function buildTargetSpec (runOptions) {
|
||||
const spec = {};
|
||||
if (runOptions.target) {
|
||||
install_target = runOptions.target;
|
||||
spec.id = runOptions.target;
|
||||
} else if (runOptions.device) {
|
||||
install_target = '--device';
|
||||
spec.type = 'device';
|
||||
} else if (runOptions.emulator) {
|
||||
install_target = '--emulator';
|
||||
spec.type = 'emulator';
|
||||
}
|
||||
return spec;
|
||||
}
|
||||
|
||||
return install_target;
|
||||
function formatResolvedTarget ({ id, type }) {
|
||||
return `${type} ${id}`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,55 +59,11 @@ module.exports.run = function (runOptions) {
|
||||
runOptions = runOptions || {};
|
||||
|
||||
var self = this;
|
||||
var install_target = getInstallTarget(runOptions);
|
||||
const spec = buildTargetSpec(runOptions);
|
||||
|
||||
return target.resolve(spec).then(function (resolvedTarget) {
|
||||
events.emit('log', `Deploying to ${formatResolvedTarget(resolvedTarget)}`);
|
||||
|
||||
return Promise.resolve().then(function () {
|
||||
if (!install_target) {
|
||||
// no target given, deploy to device if available, otherwise use the emulator.
|
||||
return device.list().then(function (device_list) {
|
||||
if (device_list.length > 0) {
|
||||
events.emit('warn', 'No target specified, deploying to device \'' + device_list[0] + '\'.');
|
||||
install_target = device_list[0];
|
||||
} else {
|
||||
events.emit('warn', 'No target specified and no devices found, deploying to emulator');
|
||||
install_target = '--emulator';
|
||||
}
|
||||
});
|
||||
}
|
||||
}).then(function () {
|
||||
if (install_target === '--device') {
|
||||
return device.resolveTarget(null);
|
||||
} else if (install_target === '--emulator') {
|
||||
// Give preference to any already started emulators. Else, start one.
|
||||
return emulator.list_started().then(function (started) {
|
||||
return started && started.length > 0 ? started[0] : emulator.start();
|
||||
}).then(function (emulatorId) {
|
||||
return emulator.resolveTarget(emulatorId);
|
||||
});
|
||||
}
|
||||
// They specified a specific device/emulator ID.
|
||||
return device.list().then(function (devices) {
|
||||
if (devices.indexOf(install_target) > -1) {
|
||||
return device.resolveTarget(install_target);
|
||||
}
|
||||
return emulator.list_started().then(function (started_emulators) {
|
||||
if (started_emulators.indexOf(install_target) > -1) {
|
||||
return emulator.resolveTarget(install_target);
|
||||
}
|
||||
return emulator.list_images().then(function (avds) {
|
||||
// if target emulator isn't started, then start it.
|
||||
for (var avd in avds) {
|
||||
if (avds[avd].name === install_target) {
|
||||
return emulator.start(install_target).then(function (emulatorId) {
|
||||
return emulator.resolveTarget(emulatorId);
|
||||
});
|
||||
}
|
||||
}
|
||||
return Promise.reject(new CordovaError(`Target '${install_target}' not found, unable to run project`));
|
||||
});
|
||||
});
|
||||
});
|
||||
}).then(function (resolvedTarget) {
|
||||
return new Promise((resolve) => {
|
||||
const buildOptions = require('./build').parseBuildOptions(runOptions, null, self.root);
|
||||
|
||||
@@ -112,7 +76,7 @@ module.exports.run = function (runOptions) {
|
||||
|
||||
resolve(self._builder.fetchBuildResults(buildOptions.buildType, buildOptions.arch));
|
||||
}).then(async function (buildResults) {
|
||||
if (resolvedTarget && resolvedTarget.isEmulator) {
|
||||
if (resolvedTarget.type === 'emulator') {
|
||||
await emulator.wait_for_boot(resolvedTarget.id);
|
||||
}
|
||||
|
||||
|
||||
Vendored
+83
-3
@@ -18,17 +18,97 @@
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
const { inspect } = require('util');
|
||||
const Adb = require('./Adb');
|
||||
const build = require('./build');
|
||||
const emulator = require('./emulator');
|
||||
const AndroidManifest = require('./AndroidManifest');
|
||||
const { compareBy } = require('./utils');
|
||||
const { retryPromise } = require('./retry');
|
||||
const { events } = require('cordova-common');
|
||||
const { events, CordovaError } = require('cordova-common');
|
||||
|
||||
const INSTALL_COMMAND_TIMEOUT = 5 * 60 * 1000;
|
||||
const NUM_INSTALL_RETRIES = 3;
|
||||
const EXEC_KILL_SIGNAL = 'SIGKILL';
|
||||
|
||||
exports.install = async function ({ target, arch, isEmulator }, buildResults) {
|
||||
/**
|
||||
* @typedef { 'device' | 'emulator' } TargetType
|
||||
* @typedef { { id: string, type: TargetType } } Target
|
||||
* @typedef { { id?: string, type?: TargetType } } TargetSpec
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns a list of available targets (connected devices & started emulators)
|
||||
*
|
||||
* @return {Promise<Target[]>}
|
||||
*/
|
||||
exports.list = async () => {
|
||||
return (await Adb.devices())
|
||||
.map(id => ({
|
||||
id,
|
||||
type: id.startsWith('emulator-') ? 'emulator' : 'device'
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {TargetSpec?} spec
|
||||
* @return {Promise<Target>}
|
||||
*/
|
||||
async function resolveToOnlineTarget (spec = {}) {
|
||||
const targetList = await exports.list();
|
||||
if (targetList.length === 0) return null;
|
||||
|
||||
// Sort by type: devices first, then emulators.
|
||||
targetList.sort(compareBy(t => t.type));
|
||||
|
||||
// Find first matching target for spec. {} matches any target.
|
||||
return targetList.find(target =>
|
||||
Object.keys(spec).every(k => spec[k] === target[k])
|
||||
) || null;
|
||||
}
|
||||
|
||||
async function isEmulatorName (name) {
|
||||
const emus = await emulator.list_images();
|
||||
return emus.some(avd => avd.name === name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TargetSpec?} spec
|
||||
* @return {Promise<Target>}
|
||||
*/
|
||||
async function resolveToOfflineEmulator (spec = {}) {
|
||||
if (spec.type === 'device') return null;
|
||||
if (spec.id && !(await isEmulatorName(spec.id))) return null;
|
||||
|
||||
// try to start an emulator with name spec.id
|
||||
// if spec.id is undefined, picks best match regarding target API
|
||||
const emulatorId = await emulator.start(spec.id);
|
||||
|
||||
return { id: emulatorId, type: 'emulator' };
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TargetSpec?} spec
|
||||
* @return {Promise<Target & {arch: string}>}
|
||||
*/
|
||||
exports.resolve = async (spec = {}) => {
|
||||
events.emit('verbose', `Trying to find target matching ${inspect(spec)}`);
|
||||
|
||||
const resolvedTarget =
|
||||
(await resolveToOnlineTarget(spec)) ||
|
||||
(await resolveToOfflineEmulator(spec));
|
||||
|
||||
if (!resolvedTarget) {
|
||||
throw new CordovaError(`Could not find target matching ${inspect(spec)}`);
|
||||
}
|
||||
|
||||
return {
|
||||
...resolvedTarget,
|
||||
arch: await build.detectArchitecture(resolvedTarget.id)
|
||||
};
|
||||
};
|
||||
|
||||
exports.install = async function ({ id: target, arch, type }, buildResults) {
|
||||
const apk_path = build.findBestApkForArchitecture(buildResults, arch);
|
||||
const manifest = new AndroidManifest(path.join(__dirname, '../../app/src/main/AndroidManifest.xml'));
|
||||
const pkgName = manifest.getPackageId();
|
||||
@@ -56,7 +136,7 @@ exports.install = async function ({ target, arch, isEmulator }, buildResults) {
|
||||
}
|
||||
}
|
||||
|
||||
if (isEmulator) {
|
||||
if (type === 'emulator') {
|
||||
// Work around sporadic emulator hangs: http://issues.apache.org/jira/browse/CB-9119
|
||||
await retryPromise(NUM_INSTALL_RETRIES, () => doInstall({
|
||||
timeout: INSTALL_COMMAND_TIMEOUT,
|
||||
|
||||
Reference in New Issue
Block a user