-
Notifications
You must be signed in to change notification settings - Fork 10
Conversation
❤️ |
@@ -12,6 +12,11 @@ class IosEmulatorServices implements Mobile.IiOSSimulatorService { | |||
return ""; | |||
} | |||
|
|||
public async getRunningEmulatorId(image: string): Promise<string> { | |||
//todo: plamen5kov: fix later if necessary | |||
return ""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should return a Promise here - return Promise.resolve("")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the async decorator does that for me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can verify this by looking at the .js code, right? Can you please share it so that we all know how it looks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments)).next());
});
};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
async generates a method that returns Promise - you can safely return the ""
.
@@ -20,6 +20,11 @@ class Wp8EmulatorServices implements Mobile.IEmulatorPlatformServices { | |||
return ""; | |||
} | |||
|
|||
public async getRunningEmulatorId(image: string): Promise<string> { | |||
//todo: plamen5kov: fix later if necessary | |||
return ""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should return a Promise here - return Promise.resolve("")
Could you also remove the 'todo' and instead add a comment that it's an empty stub?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer leaving the todo untill all the tests in master pass.
let result: string[] = []; | ||
if (this.$fs.exists(this.avdDir)) { | ||
let entries = this.$fs.readDirectory(this.avdDir); | ||
result = _.filter(entries, (e: string) => e.match(AndroidEmulatorServices.INI_FILES_MASK) !== null) | ||
.map((e) => e.match(AndroidEmulatorServices.INI_FILES_MASK)[1]); | ||
} | ||
return result; | ||
if (suggestedImage && !_.includes(result, suggestedImage)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest we simplify and refactor this a little bit. It took me a lot of time to understand the flow here.
Why not getAvds to return just the AVDs and then we can filter them out when we have to?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You got a point. Will fix.
let result: string[] = []; | ||
if (this.$fs.exists(this.avdDir)) { | ||
let entries = this.$fs.readDirectory(this.avdDir); | ||
result = _.filter(entries, (e: string) => e.match(AndroidEmulatorServices.INI_FILES_MASK) !== null) | ||
.map((e) => e.match(AndroidEmulatorServices.INI_FILES_MASK)[1]); | ||
} | ||
return result; | ||
if (suggestedImage && !_.includes(result, suggestedImage)) { | ||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When we return null, I guess null.map()... would throw an exception below in getBestFit(). One more reason for refactoring
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
let foundDevices = this.getDeviceInstances(); | ||
|
||
//if no --device is passed and no devices are found, the default emulator is started | ||
if (data && data.platform && !data.deviceId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not fail with an error in the beginning if !data || !data.platform? we move this check everywhere below and it's something I think this method cannot operate correctly without anyway?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To improve readability I would suggest something like: if(!data.deviceId && _.isEmpty(foundDevices)) { }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not fail with an error in the beginning if !data || !data.platform?
Because there's common code that will use this functionality and won't need platform specified
|
||
// are there any running devices | ||
await this.detectCurrentlyAttachedDevices(); | ||
let foundDevices = this.getDeviceInstances(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rename this variable to deviceInstances to be consistent with the method - getDeviceInstances
|
||
//check if --device(value) is running, if it's not or it's not the same as is specified, start with name from --device(value) | ||
if (data && data.platform && data.deviceId) { | ||
if (!helpers.isNumber(data.deviceId)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if the deviceId is a number? Is it incorrect for deviceId? What's the format of the device Id and do we need to validate this here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this context, we only care if the deviceId is an image that we need to start the emulator from. If it's a number, we don't need to do anything
//check if --device(value) is running, if it's not or it's not the same as is specified, start with name from --device(value) | ||
if (data && data.platform && data.deviceId) { | ||
if (!helpers.isNumber(data.deviceId)) { | ||
let searchedDevice = _.find(this.getDeviceInstances(), (device: Mobile.IDevice) => { return device.deviceInfo.identifier === data.deviceId; }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rename this to just "activeDeviceInstance" then it would be meaningful to have if(!activeDeviceInstance) { start one for me}
|
||
// if only emulator flag is passed and no other emulators are running, start default emulator | ||
if (data && data.platform && data.emulator && foundDevices.length) { | ||
let atLeastOneEmulator = _.some(foundDevices, (value) => {return value.isEmulator; }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this would be "runningDeviceInstance" I guess?
if (data && data.platform && data.emulator && foundDevices.length) { | ||
let atLeastOneEmulator = _.some(foundDevices, (value) => {return value.isEmulator; }); | ||
if (!atLeastOneEmulator) { | ||
return await this.startEmulator(data.platform); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does the --emulator flag support --emulatorId or a like for it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--emulator flag is boolean, if you want to specify the emulator --device flag should be used.
* Returns true if there's a running device with specified identifier. | ||
* @param identifier parameter passed by the user to --device flag | ||
*/ | ||
private async hasDevice(identifier: string): Promise<boolean> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per the comment of the method I would make it more self-descriptive as "hasRunningDevice"
💔 |
* Returns true if there's a running device with specified identifier. | ||
* @param identifier parameter passed by the user to --device flag | ||
*/ | ||
private async hasDevice(identifier: string): Promise<boolean> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think any async operations are ran in the method.
emulatorIdentifier = await emulatorService.getRunningEmulatorId(deviceOption); | ||
} | ||
|
||
if (await this.hasDevice(emulatorIdentifier)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the await
if this.hasDevice
becomes synchronous.
@@ -117,7 +117,7 @@ class AndroidEmulatorServices implements Mobile.IAndroidEmulatorServices { | |||
// unlock screen | |||
await this.unlockScreen(emulatorId); | |||
} else { | |||
this.$errors.fail("Could not find an emulator image to run your project."); | |||
this.$errors.fail(`Could not find an emulator image or identifier to run your project. Please run: "tns run <platform> --available-devices"`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sure to change this one if tns devices
will be used in favor of run --available devices
@@ -217,6 +220,11 @@ export class DevicesService implements Mobile.IDevicesService { | |||
await this.getDeviceDetectionIntervalFuture(); | |||
} | |||
|
|||
/** | |||
* Returns device that maches an identifier. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[minor] maches -> maTches typo
💔 |
bootstrap.ts
Outdated
$injector.requireCommand("device|android", "./commands/device/list-devices"); | ||
$injector.requireCommand("device|ios", "./commands/device/list-devices"); | ||
$injector.requireCommand(["device|android", "devices|android"], "./commands/device/list-devices"); | ||
$injector.requireCommand(["device|ios", "devics|ios"], "./commands/device/list-devices"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: devics|
commands/device/list-devices.ts
Outdated
@@ -65,4 +72,4 @@ class ListiOSDevicesCommand implements ICommand { | |||
} | |||
} | |||
|
|||
$injector.registerCommand("device|ios", ListiOSDevicesCommand); | |||
$injector.registerCommand(["device|ios", "devics|ios"], ListiOSDevicesCommand); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: devics
let minVersion = this.$emulatorSettingsService.minVersion; | ||
|
||
let best = _(this.getAvds()) | ||
let avdResults = this.getAvds(); | ||
if (suggestedImage && !_.includes(avdResults, suggestedImage)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole if/else can be simplified even further to just one filter:
if(suggestedImage) {
avgResults = avgResults.filter(avd => avd === suggestedImage);
}
} | ||
|
||
// if only emulator flag is passed and no other emulators are running, start default emulator | ||
if (data && data.platform && data.emulator && deviceInstances.length) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can validate the data && data.platform in the beginning of the method - it's included in all If statements in this method
💔 |
252c027
to
2fe8654
Compare
💔 |
1 similar comment
💔 |
@@ -117,7 +117,7 @@ class AndroidEmulatorServices implements Mobile.IAndroidEmulatorServices { | |||
// unlock screen | |||
await this.unlockScreen(emulatorId); | |||
} else { | |||
this.$errors.fail("Could not find an emulator image to run your project."); | |||
this.$errors.fail(`Could not find an emulator image or identifier to run your project. Please run: "tns device <platform> --available-devices"`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this code is used in different CLIs. In case you want to specify command that the user should execute, you can use something like:
his.$errors.fail(`Could not find an emulator image or identifier to run your project. Please run: "${this.$staticConfig.CLIENT_NAME} device <platform> --available-devices"`);
emulatorIdentifier = await emulatorService.getRunningEmulatorId(deviceOption); | ||
} | ||
|
||
if (this.hasRunningDevice(emulatorIdentifier)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this code is correct. In case I have running emulator and device attached, if I use any command with --device <my connected real device identifier>
, the current code will still return the emulator instance, which is not what I want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We pass the emulatorIdentifier from `emulatorService.getRunningEmulatorId(). Try it out: if the case is, connected emulator and a connected device and you want to run on the emulator you can do the following:
tns run android --device <emulator_index>
tns run android --device <emulator-5554/6 ...>
tns run android --device <emulator_image>
This will start the app only on the specified emulator.
If it's a device you want:
tns run android --device <device_identifier>
tns run android --device <device_index>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please excuse me, totally my mistake - emulatorIdentifier will be falsey value in case I've specified the identifier of the real device
public async startEmulatorIfNecessary(data?: Mobile.IDevicesServicesInitializationOptions): Promise<void> { | ||
if (data && data.deviceId && data.emulator) { | ||
this.$errors.failWithoutHelp(`--device and –emulator are incompatible options. | ||
If you are trying to run on specific emulator, use tns run –device <DeviceID>.`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
`--device and --emulator are incompatible options. If you are trying to run on specific emulator, use "${this.$staticConfig.CLIENT_NAME} run --device <DeviceID>.`
|
||
// if only emulator flag is passed and no other emulators are running, start default emulator | ||
if (data.emulator && deviceInstances.length) { | ||
let runningDeviceInstance = _.some(deviceInstances, (value) => {return value.isEmulator; }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could be shorten:
const runningDeviceInstance = _.some(deviceInstances, value => value.isEmulator);
@@ -437,6 +440,8 @@ describe("devicesService", () => { | |||
it("does not fail when androidDeviceDiscovery startLookingForDevices fails", async () => { | |||
(<any>androidDeviceDiscovery).startLookingForDevices = (): Promise<void> => { throw new Error("my error"); }; | |||
iOSDeviceDiscovery.emit("deviceFound", iOSDevice); | |||
let hostInfo = testInjector.resolve("hostInfo"); | |||
hostInfo.isDarwin = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this code added?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The purpose of the test is to check if startLookingForDevices
fails, which is in no way compromised by adding hostInfo.isDarwin. It's used to resolve an emulator service, and by that time the test has either failed or not.
services/image-service.ts
Outdated
import { createTable } from "../helpers"; | ||
|
||
//todo: plamen5kov: moved most of emulator-service here as a temporary solution untill after 3.0-RC | ||
export class ImageService implements Mobile.IImageService { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm, why is this called ImageService? This way I would think it works with images, for example in App_Resources dir.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could rename it to EmulatorImageService if it would be more readable?
@@ -469,6 +474,8 @@ describe("devicesService", () => { | |||
assert.isFalse(devicesService.hasDevices, "Initially devicesService hasDevices must be false."); | |||
iOSDeviceDiscovery.emit("deviceFound", iOSDevice); | |||
androidDeviceDiscovery.emit("deviceFound", androidDevice); | |||
let hostInfo = testInjector.resolve("hostInfo"); | |||
hostInfo.isDarwin = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here - the test should be platform independent - why should we set the OS to be macOS ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I planed to change this test. Will update it with correct message, in appliance with refactoring.
4950d06
to
24af78c
Compare
❤️ |
add comments to devices-service updated tests after logical changes * removed startEmulator functionality from initialize, so we dont expect emulator to be started by initialize in any case anymore * in initialize we first check the platform, because other functionality depends on it * getDevice method should work even withrout platform specified (at least the test say so) fixed running emulator by index Pass the device id to the startEmulator. removed method we do not want to support made lint happy added available-devices option to mobile-cli-lib added alias for tns device: devices updates after review updated tests to check if emulators are started in specific cases updated getAvds logic and getbestFit to improve readability updates after review typo, field and method renamings fixed typos simplify code refactoring after review
24af78c
to
363a40e
Compare
❤️ |
❤️ |
Moved functionality from
tns emulate
totns run
command.Main changes:
Device Identifier
for both android and ios emulators/simulatorsDevice Identifier
and index.related issue: NativeScript/nativescript-cli#2349