Skip to content

Commit 93b36c2

Browse files
FatmeFatme Havaluova
authored and
Fatme Havaluova
committed
Deploy on emulator
1 parent 7b9f5c4 commit 93b36c2

14 files changed

+161
-60
lines changed

lib/bootstrap.ts

+3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ $injector.require("platformService", "./services/platform-service");
1515
$injector.require("userSettingsService", "./services/user-settings-service");
1616
$injector.require("analyticsSettingsService", "./services/analytics-settings-service");
1717

18+
$injector.require("emulatorSettingsService", "./services/emulator-settings-service");
19+
1820
$injector.requireCommand("create", "./commands/create-project");
1921
$injector.requireCommand("platform|*list", "./commands/list-platforms");
2022
$injector.requireCommand("platform|add", "./commands/add-platform");
@@ -24,6 +26,7 @@ $injector.requireCommand("prepare", "./commands/prepare");
2426
$injector.requireCommand("build", "./commands/build");
2527
$injector.requireCommand("deploy", "./commands/deploy");
2628
$injector.requireCommand("dev-post-install", "./commands/post-install");
29+
$injector.requireCommand("emulate", "./commands/emulate");
2730

2831
$injector.require("npm", "./node-package-manager");
2932
$injector.require("config", "./config");

lib/commands/deploy.ts

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
///<reference path="../.d.ts"/>
22

3-
export class DeployCommand implements ICommand {
3+
export class DeployOnDeviceCommand implements ICommand {
44
constructor(private $platformService: IPlatformService) { }
55

66
execute(args: string[]): IFuture<void> {
7-
return (() => {
8-
this.$platformService.deploy(args[0]).wait();
9-
}).future<void>()();
7+
return this.$platformService.deployOnDevice(args[0]);
108
}
119
}
12-
$injector.registerCommand("deploy", DeployCommand);
10+
$injector.registerCommand("deploy", DeployOnDeviceCommand);

lib/commands/emulate.ts

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
///<reference path="../.d.ts"/>
2+
3+
export class EmulateCommand implements ICommand {
4+
constructor(private $platformService: IPlatformService) { }
5+
6+
execute(args: string[]): IFuture<void> { return this.$platformService.deployOnEmulator(args[0]);}
7+
}
8+
$injector.registerCommand("emulate", EmulateCommand);

lib/declarations.ts

+5
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,8 @@ interface INodePackageManager {
66

77
interface IStaticConfig extends Config.IStaticConfig { }
88

9+
interface IApplicationPackage {
10+
packageName: string;
11+
time: Date;
12+
}
13+

lib/definitions/platform.d.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,20 @@ interface IPlatformService {
66
runPlatform(platform: string): IFuture<void>;
77
preparePlatform(platform: string): IFuture<void>;
88
buildPlatform(platform: string): IFuture<void>;
9-
deploy(platform: string): IFuture<void>;
9+
deployOnDevice(platform: string): IFuture<void>;
10+
deployOnEmulator(platform: string): IFuture<void>;
1011
}
1112

1213
interface IPlatformData {
1314
frameworkPackageName: string;
1415
platformProjectService: IPlatformProjectService;
16+
emulatorServices: Mobile.IEmulatorPlatformServices;
1517
projectRoot: string;
1618
normalizedPlatformName: string;
17-
buildOutputPath: string;
18-
validPackageNames: string[];
19+
deviceBuildOutputPath: string;
20+
emulatorBuildOutputPath?: string;
21+
validPackageNamesForDevice: string[];
22+
validPackageNamesForEmulator?: string[];
1923
targetedOS?: string[];
2024
}
2125

lib/options.ts

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ var knownOpts:any = {
1313
"link-to": String,
1414
"release": String,
1515
"device": Boolean,
16+
"emulator": Boolean,
1617
"version": Boolean,
1718
"help": Boolean
1819
},

lib/services/android-project-service.ts

+9-7
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,22 @@ class AndroidProjectService implements IPlatformProjectService {
1010
private targetApi: string;
1111

1212
constructor(private $fs: IFileSystem,
13-
private $errors: IErrors,
14-
private $logger: ILogger,
15-
private $childProcess: IChildProcess,
16-
private $projectData: IProjectData,
17-
private $propertiesParser: IPropertiesParser) { }
13+
private $errors: IErrors,
14+
private $logger: ILogger,
15+
private $childProcess: IChildProcess,
16+
private $projectData: IProjectData,
17+
private $propertiesParser: IPropertiesParser,
18+
private $androidEmulatorServices: Mobile.IEmulatorPlatformServices) { }
1819

1920
public get platformData(): IPlatformData {
2021
return {
2122
frameworkPackageName: "tns-android",
2223
normalizedPlatformName: "Android",
2324
platformProjectService: this,
25+
emulatorServices: this.$androidEmulatorServices,
2426
projectRoot: path.join(this.$projectData.platformsDir, "android"),
25-
buildOutputPath: path.join(this.$projectData.platformsDir, "android", "bin"),
26-
validPackageNames: [
27+
deviceBuildOutputPath: path.join(this.$projectData.platformsDir, "android", "bin"),
28+
validPackageNamesForDevice: [
2729
util.format("%s-%s.%s", this.$projectData.projectName, "debug", "apk"),
2830
util.format("%s-%s.%s", this.$projectData.projectName, "release", "apk")
2931
]
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
///<reference path="../.d.ts"/>
2+
3+
export class EmulatorSettingsService implements Mobile.IEmulatorSettingsService {
4+
private static REQURED_ANDROID_APILEVEL = 17;
5+
6+
constructor(private $injector: IInjector) { }
7+
8+
public canStart(platform: string): IFuture<boolean> {
9+
return (() => {
10+
var platformService = this.$injector.resolve("platformService"); // this should be resolved here due to cyclic dependency
11+
12+
var installedPlatforms = platformService.getInstalledPlatforms().wait();
13+
return _.contains(installedPlatforms, platform.toLowerCase());
14+
}).future<boolean>()();
15+
}
16+
17+
public get minVersion(): number {
18+
return EmulatorSettingsService.REQURED_ANDROID_APILEVEL;
19+
}
20+
}
21+
$injector.register("emulatorSettingsService", EmulatorSettingsService);

lib/services/ios-project-service.ts

+21-13
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,24 @@ class IOSProjectService implements IPlatformProjectService {
1515
constructor(private $projectData: IProjectData,
1616
private $fs: IFileSystem,
1717
private $childProcess: IChildProcess,
18-
private $errors: IErrors) { }
18+
private $errors: IErrors,
19+
private $iOSEmulatorServices: Mobile.IEmulatorPlatformServices) { }
1920

2021
public get platformData(): IPlatformData {
2122
return {
2223
frameworkPackageName: "tns-ios",
2324
normalizedPlatformName: "iOS",
2425
platformProjectService: this,
26+
emulatorServices: this.$iOSEmulatorServices,
2527
projectRoot: path.join(this.$projectData.platformsDir, "ios"),
26-
buildOutputPath: path.join(this.$projectData.platformsDir, "ios", "build", "device"),
27-
validPackageNames: [
28+
deviceBuildOutputPath: path.join(this.$projectData.platformsDir, "ios", "build", "device"),
29+
emulatorBuildOutputPath: path.join(this.$projectData.platformsDir, "ios", "build", "emulator"),
30+
validPackageNamesForDevice: [
2831
this.$projectData.projectName + ".ipa"
2932
],
33+
validPackageNamesForEmulator: [
34+
this.$projectData.projectName + ".app"
35+
],
3036
targetedOS: ['darwin']
3137
};
3238
}
@@ -117,18 +123,20 @@ class IOSProjectService implements IPlatformProjectService {
117123
var childProcess = this.$childProcess.spawn("xcodebuild", args, {cwd: options, stdio: 'inherit'});
118124
this.$fs.futureFromEvent(childProcess, "exit").wait();
119125

120-
var buildOutputPath = path.join(projectRoot, "build", options.device ? "device" : "emulator");
126+
if(options.device) {
127+
var buildOutputPath = path.join(projectRoot, "build", options.device ? "device" : "emulator");
121128

122-
// Produce ipa file
123-
var xcrunArgs = [
124-
"-sdk", "iphoneos",
125-
"PackageApplication",
126-
"-v", path.join(buildOutputPath, this.$projectData.projectName + ".app"),
127-
"-o", path.join(buildOutputPath, this.$projectData.projectName + ".ipa")
128-
];
129+
// Produce ipa file
130+
var xcrunArgs = [
131+
"-sdk", "iphoneos",
132+
"PackageApplication",
133+
"-v", path.join(buildOutputPath, this.$projectData.projectName + ".app"),
134+
"-o", path.join(buildOutputPath, this.$projectData.projectName + ".ipa")
135+
];
129136

130-
var childProcess = this.$childProcess.spawn("xcrun", xcrunArgs, {cwd: options, stdio: 'inherit'});
131-
this.$fs.futureFromEvent(childProcess, "exit").wait();
137+
var childProcess = this.$childProcess.spawn("xcrun", xcrunArgs, {cwd: options, stdio: 'inherit'});
138+
this.$fs.futureFromEvent(childProcess, "exit").wait();
139+
}
132140
}).future<void>()();
133141
}
134142

lib/services/platform-service.ts

+74-31
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,11 @@ export class PlatformService implements IPlatformService {
164164
platform = platform.toLowerCase();
165165

166166
this.preparePlatform(platform).wait();
167-
168-
// We need to set device option here
169-
var cachedDeviceOption = options.device;
170-
options.device = true;
171-
this.buildPlatform(platform).wait();
172-
options.device = cachedDeviceOption;
173-
174-
this.deploy(platform).wait();
167+
if(options.emulator) {
168+
this.deployOnEmulator(platform).wait();
169+
} else {
170+
this.deployOnDevice(platform).wait();
171+
}
175172
}).future<void>()();
176173
}
177174

@@ -191,35 +188,21 @@ export class PlatformService implements IPlatformService {
191188
}).future<void>()();
192189
}
193190

194-
public deploy(platform: string): IFuture<void> {
191+
public deployOnDevice(platform: string): IFuture<void> {
195192
return (() => {
196-
platform = platform.toLowerCase();
197-
198193
this.validatePlatformInstalled(platform);
194+
platform = platform.toLowerCase();
199195

200196
var platformData = this.$platformsData.getPlatformData(platform);
201197

202-
// Get latest package that is produced from build
203-
var candidates = this.$fs.readDirectory(platformData.buildOutputPath).wait();
204-
var packages = _.filter(candidates, candidate => {
205-
return _.contains(platformData.validPackageNames, candidate);
206-
}).map(currentPackage => {
207-
currentPackage = path.join(platformData.buildOutputPath, currentPackage);
208-
209-
return {
210-
pkg: currentPackage,
211-
time: this.$fs.getFsStats(currentPackage).wait().mtime
212-
};
213-
});
214-
215-
packages = _.sortBy(packages, pkg => pkg.time ).reverse(); // We need to reverse because sortBy always sorts in ascending order
216-
217-
if(packages.length === 0) {
218-
var packageExtName = path.extname(platformData.validPackageNames[0]);
219-
this.$errors.fail("No %s found in %s directory", packageExtName, platformData.buildOutputPath)
220-
}
198+
// We need to build for device
199+
var cachedDeviceOption = options.device;
200+
options.device = true;
201+
this.buildPlatform(platform).wait();
202+
options.device = cachedDeviceOption;
221203

222-
var packageFile = packages[0].pkg;
204+
// Get latest package that is produced from build
205+
var packageFile = this.getLatestApplicationPackageForDevice(platformData).wait().packageName;
223206
this.$logger.out("Using ", packageFile);
224207

225208
this.$devicesServices.initialize(platform, options.device).wait();
@@ -229,6 +212,25 @@ export class PlatformService implements IPlatformService {
229212
}).future<void>()();
230213
}
231214

215+
public deployOnEmulator(platform: string): IFuture<void> {
216+
return (() => {
217+
this.validatePlatformInstalled(platform);
218+
platform = platform.toLowerCase();
219+
220+
var platformData = this.$platformsData.getPlatformData(platform);
221+
var emulatorServices = platformData.emulatorServices;
222+
223+
emulatorServices.checkAvailability().wait();
224+
225+
this.buildPlatform(platform).wait();
226+
227+
var packageFile = this.getLatestApplicationPackageForEmulator(platformData).wait().packageName;
228+
this.$logger.out("Using ", packageFile);
229+
230+
emulatorServices.startEmulator(packageFile, options.emulator).wait();
231+
}).future<void>()();
232+
}
233+
232234
private validatePlatform(platform: string): void {
233235
if(!platform) {
234236
this.$errors.fail("No platform specified.")
@@ -299,5 +301,46 @@ export class PlatformService implements IPlatformService {
299301
});
300302
}).future<void>()();
301303
}
304+
305+
private getApplicationPackages(buildOutputPath: string, validPackageNames: string[]): IFuture<IApplicationPackage[]> {
306+
return (() => {
307+
// Get latest package that is produced from build
308+
var candidates = this.$fs.readDirectory(buildOutputPath).wait();
309+
var packages = _.filter(candidates, candidate => {
310+
return _.contains(validPackageNames, candidate);
311+
}).map(currentPackage => {
312+
currentPackage = path.join(buildOutputPath, currentPackage);
313+
314+
return {
315+
packageName: currentPackage,
316+
time: this.$fs.getFsStats(currentPackage).wait().mtime
317+
};
318+
});
319+
320+
return packages;
321+
}).future<IApplicationPackage[]>()();
322+
}
323+
324+
private getLatestApplicationPackage(buildOutputPath: string, validPackageNames: string[]): IFuture<IApplicationPackage> {
325+
return (() => {
326+
var packages = this.getApplicationPackages(buildOutputPath, validPackageNames).wait();
327+
if (packages.length === 0) {
328+
var packageExtName = path.extname(validPackageNames[0]);
329+
this.$errors.fail("No %s found in %s directory", packageExtName, buildOutputPath);
330+
}
331+
332+
packages = _.sortBy(packages, pkg => pkg.time).reverse(); // We need to reverse because sortBy always sorts in ascending order
333+
334+
return packages[0];
335+
}).future<IApplicationPackage>()();
336+
}
337+
338+
private getLatestApplicationPackageForDevice(platformData: IPlatformData) {
339+
return this.getLatestApplicationPackage(platformData.deviceBuildOutputPath, platformData.validPackageNamesForDevice);
340+
}
341+
342+
private getLatestApplicationPackageForEmulator(platformData: IPlatformData) {
343+
return this.getLatestApplicationPackage(platformData.emulatorBuildOutputPath || platformData.deviceBuildOutputPath, platformData.validPackageNamesForEmulator || platformData.validPackageNamesForDevice);
344+
}
302345
}
303346
$injector.register("platformService", PlatformService);

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"ffi": "https://github.com/icenium/node-ffi/tarball/master",
3030
"fibers": "https://github.com/icenium/node-fibers/tarball/master",
3131
"filesize": "2.0.3",
32+
"iconv-lite": "0.4.4",
3233
"log4js": "0.6.9",
3334
"mkdirp": "0.3.5",
3435
"mute-stream": "0.0.4",

resources/help.txt

+6
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,12 @@ Runs your project on a connected device. This is shorthand for prepare, build, a
171171

172172
--[/]--
173173

174+
--[emulate]--
175+
176+
Usage:
177+
$ tns emulate [<platform>]
178+
--[/]--
179+
174180
--[feature-usage-tracking]--
175181

176182
Usage:

test/platform-service.ts

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ testInjector.register('npm', stubs.NPMStub);
1818
testInjector.register('projectData', stubs.ProjectDataStub);
1919
testInjector.register('platformsData', stubs.PlatformsDataStub);
2020
testInjector.register('devicesServices', {});
21+
testInjector.register('androidEmulatorServices', {});
2122

2223
describe('PlatformService', function(){
2324
describe('#updatePlatforms()', function(){

0 commit comments

Comments
 (0)