Skip to content

Commit f67f722

Browse files
FatmeFatme Havaluova
authored andcommitted
Deploy to connected device
1 parent 42854fa commit f67f722

22 files changed

+34606
-25
lines changed

lib/bootstrap.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ $injector.requireCommand("platform|remove", "./commands/remove-platform");
2222
$injector.requireCommand("run", "./commands/run");
2323
$injector.requireCommand("prepare", "./commands/prepare");
2424
$injector.requireCommand("build", "./commands/build");
25+
$injector.requireCommand("deploy", "./commands/deploy");
2526

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

lib/commands/deploy.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
///<reference path="../.d.ts"/>
2+
3+
export class DeployCommand implements ICommand {
4+
constructor(private $platformService: IPlatformService) { }
5+
6+
execute(args: string[]): IFuture<void> {
7+
return (() => {
8+
this.$platformService.deploy(args[0]).wait();
9+
}).future<void>()();
10+
}
11+
}
12+
$injector.registerCommand("deploy", DeployCommand);

lib/config.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
11
///<reference path=".d.ts"/>
22

33
import path = require("path");
4+
import util = require("util");
45

56
export class StaticConfig implements IStaticConfig {
67
public PROJECT_FILE_NAME = ".tnsproject";
78
public CLIENT_NAME = "tns";
89
public ANALYTICS_API_KEY = "5752dabccfc54c4ab82aea9626b7338e";
910
public TRACK_FEATURE_USAGE_SETTING_NAME = "TrackFeatureUsage";
1011
public ANALYTICS_INSTALLATION_ID_SETTING_NAME = "AnalyticsInstallationID";
12+
public START_PACKAGE_ACTIVITY_NAME = "com.tns.NativeScriptActivity";
1113

1214
public version = require("../package.json").version;
1315

14-
public get helpTextPath() {
16+
public get helpTextPath(): string {
1517
return path.join(__dirname, "../resources/help.txt");
1618
}
19+
20+
public get adbFilePath(): string {
21+
return path.join(__dirname, util.format("../resources/platform-tools/android/%s/adb", process.platform));
22+
}
1723
}
1824
$injector.register("staticConfig", StaticConfig);

lib/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
///<reference path=".d.ts"/>
22

33
export var APP_FOLDER_NAME = "app";
4+
export var TNS_MODULES_FOLDER_NAME = "tns_modules";
45
export var DEFAULT_PROJECT_ID = "com.telerik.tns.HelloWorld";
56
export var DEFAULT_PROJECT_NAME = "HelloNativescript";
67
export var APP_RESOURCES_FOLDER_NAME = "App_Resources";

lib/definitions/platform.d.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,20 @@ interface IPlatformService {
22
addPlatforms(platforms: string[]): IFuture<void>;
33
getInstalledPlatforms(): IFuture<string[]>;
44
getAvailablePlatforms(): IFuture<string[]>;
5+
removePlatforms(platforms: string[]): IFuture<void>;
56
runPlatform(platform: string): IFuture<void>;
67
preparePlatform(platform: string): IFuture<void>;
78
buildPlatform(platform: string): IFuture<void>;
8-
removePlatforms(platforms: string[]): IFuture<void>;
9+
deploy(platform: string): IFuture<void>;
910
}
1011

1112
interface IPlatformData {
1213
frameworkPackageName: string;
1314
platformProjectService: IPlatformProjectService;
1415
projectRoot: string;
1516
normalizedPlatformName: string;
17+
buildOutputPath: string;
18+
validPackageNames: string[];
1619
targetedOS?: string[];
1720
}
1821

lib/nativescript-cli.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ $injector.register("config", {
1616
DEBUG: process.env.NATIVESCRIPT_DEBUG,
1717
version: require("../package.json").version,
1818
helpTextPath: path.join(__dirname, "../resources/help.txt"),
19-
client: "tns"
19+
client: "nativescript"
2020
});
2121

2222
var dispatcher = $injector.resolve("dispatcher");

lib/services/android-project-service.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import path = require("path");
33
import shell = require("shelljs");
44
import util = require("util");
55
import options = require("./../options");
6-
import helpers = require("./../common/helpers");
76
import constants = require("./../constants");
7+
import hostInfo = require("../common/host-info");
88

99
class AndroidProjectService implements IPlatformProjectService {
1010
private targetApi: string;
@@ -21,7 +21,12 @@ class AndroidProjectService implements IPlatformProjectService {
2121
frameworkPackageName: "tns-android",
2222
normalizedPlatformName: "Android",
2323
platformProjectService: this,
24-
projectRoot: path.join(this.$projectData.platformsDir, "android")
24+
projectRoot: path.join(this.$projectData.platformsDir, "android"),
25+
buildOutputPath: path.join(this.$projectData.platformsDir, "android", "bin"),
26+
validPackageNames: [
27+
util.format("%s-%s.%s", this.$projectData.projectName, "debug", "apk"),
28+
util.format("%s-%s.%s", this.$projectData.projectName, "release", "apk")
29+
]
2530
};
2631
}
2732

@@ -84,15 +89,15 @@ class AndroidProjectService implements IPlatformProjectService {
8489
var assetsDirectory = path.join(platformData.projectRoot, "assets");
8590
var resDirectory = path.join(platformData.projectRoot, "res");
8691

87-
shell.cp("-r", appSourceDirectory, assetsDirectory);
92+
shell.cp("-r", path.join(appSourceDirectory, "*"), assetsDirectory);
8893

89-
var appResourcesDirectoryPath = path.join(assetsDirectory, constants.APP_FOLDER_NAME, constants.APP_RESOURCES_FOLDER_NAME);
94+
var appResourcesDirectoryPath = path.join(assetsDirectory, constants.APP_RESOURCES_FOLDER_NAME);
9095
if (this.$fs.exists(appResourcesDirectoryPath).wait()) {
9196
shell.cp("-r", path.join(appResourcesDirectoryPath, platformData.normalizedPlatformName, "*"), resDirectory);
9297
this.$fs.deleteDirectory(appResourcesDirectoryPath).wait();
9398
}
9499

95-
return path.join(assetsDirectory, constants.APP_FOLDER_NAME);
100+
return assetsDirectory;
96101

97102
}).future<string>()();
98103
}
@@ -106,7 +111,7 @@ class AndroidProjectService implements IPlatformProjectService {
106111
}
107112

108113
private spawn(command: string, args: string[]): IFuture<void> {
109-
if (helpers.isWindows()) {
114+
if (hostInfo.isWindows()) {
110115
args.unshift('/s', '/c', command);
111116
command = 'cmd';
112117
}
@@ -124,7 +129,8 @@ class AndroidProjectService implements IPlatformProjectService {
124129
return (() => {
125130
var args = [
126131
"--path", projectPath,
127-
"--target", targetApi
132+
"--target", targetApi,
133+
"--name", this.$projectData.projectName
128134
];
129135

130136
this.spawn("android", ['update', 'project'].concat(args)).wait();

lib/services/ios-project-service.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ class IOSProjectService implements IPlatformProjectService {
2323
normalizedPlatformName: "iOS",
2424
platformProjectService: this,
2525
projectRoot: path.join(this.$projectData.platformsDir, "ios"),
26+
buildOutputPath: path.join(this.$projectData.platformsDir, "ios", "build", "device"),
27+
validPackageNames: [
28+
this.$projectData.projectName + ".ipa"
29+
],
2630
targetedOS: ['darwin']
2731
};
2832
}
@@ -76,9 +80,10 @@ class IOSProjectService implements IPlatformProjectService {
7680
return (() => {
7781
var appSourceDirectory = path.join(this.$projectData.projectDir, constants.APP_FOLDER_NAME);
7882
var appDestinationDirectory = path.join(platformData.projectRoot, this.$projectData.projectName);
79-
shell.cp("-r", appSourceDirectory, appDestinationDirectory);
8083

81-
return path.join(appDestinationDirectory, constants.APP_FOLDER_NAME);
84+
shell.cp("-r", path.join(appSourceDirectory, "*"), appDestinationDirectory);
85+
86+
return appDestinationDirectory;
8287
}).future<string>()();
8388
}
8489

@@ -87,7 +92,7 @@ class IOSProjectService implements IPlatformProjectService {
8792
var basicArgs = [
8893
"-project", path.join(projectRoot, this.$projectData.projectName + ".xcodeproj"),
8994
"-target", this.$projectData.projectName,
90-
"-configuration", options.release ? "Release": "Debug",
95+
"-configuration", options.release ? "Release" : "Debug",
9196
"build"
9297
];
9398
var args: string[] = [];
@@ -112,6 +117,18 @@ class IOSProjectService implements IPlatformProjectService {
112117
var childProcess = this.$childProcess.spawn("xcodebuild", args, {cwd: options, stdio: 'inherit'});
113118
this.$fs.futureFromEvent(childProcess, "exit").wait();
114119

120+
var buildOutputPath = path.join(projectRoot, "build", options.device ? "device" : "emulator");
121+
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+
130+
var childProcess = this.$childProcess.spawn("xcrun", xcrunArgs, {cwd: options, stdio: 'inherit'});
131+
this.$fs.futureFromEvent(childProcess, "exit").wait();
115132
}).future<void>()();
116133
}
117134

lib/services/platform-service.ts

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import shell = require("shelljs");
55
import util = require("util");
66
import constants = require("./../constants");
77
import helpers = require("./../common/helpers");
8+
import options = require("./../options");
89

910
class PlatformsData implements IPlatformsData {
1011
private platformsData : { [index: string]: any } = {};
@@ -34,7 +35,8 @@ export class PlatformService implements IPlatformService {
3435
private $logger: ILogger,
3536
private $npm: INodePackageManager,
3637
private $projectData: IProjectData,
37-
private $platformsData: IPlatformsData) { }
38+
private $platformsData: IPlatformsData,
39+
private $devicesServices: Mobile.IDevicesServices) { }
3840

3941
public addPlatforms(platforms: string[]): IFuture<void> {
4042
return (() => {
@@ -138,17 +140,9 @@ export class PlatformService implements IPlatformService {
138140
var platformProjectService = platformData.platformProjectService;
139141

140142
var appFilesLocation = platformProjectService.prepareProject(platformData).wait();
141-
var files = helpers.enumerateFilesInDirectorySync(appFilesLocation);
142143

143-
_.each(files, fileName => {
144-
var platformInfo = PlatformService.parsePlatformSpecificFileName(path.basename(fileName), this.$platformsData.platformsNames);
145-
var shouldExcludeFile = platformInfo && platformInfo.platform !== platform;
146-
if (shouldExcludeFile) {
147-
this.$fs.deleteFile(fileName).wait();
148-
} else if (platformInfo && platformInfo.onDeviceName) {
149-
this.$fs.rename(fileName, path.join(path.dirname(fileName), platformInfo.onDeviceName)).wait();
150-
}
151-
});
144+
this.processPlatformSpecificFiles(platform, helpers.enumerateFilesInDirectorySync(path.join(appFilesLocation, constants.APP_FOLDER_NAME))).wait();
145+
this.processPlatformSpecificFiles(platform, helpers.enumerateFilesInDirectorySync(path.join(appFilesLocation, constants.TNS_MODULES_FOLDER_NAME))).wait();
152146

153147
}).future<void>()();
154148
}
@@ -170,7 +164,14 @@ export class PlatformService implements IPlatformService {
170164
platform = platform.toLowerCase();
171165

172166
this.preparePlatform(platform).wait();
167+
168+
// We need to set device option here
169+
var cachedDeviceOption = options.device;
170+
options.device = true;
173171
this.buildPlatform(platform).wait();
172+
options.device = cachedDeviceOption;
173+
174+
this.deploy(platform).wait();
174175
}).future<void>()();
175176
}
176177

@@ -190,6 +191,44 @@ export class PlatformService implements IPlatformService {
190191
}).future<void>()();
191192
}
192193

194+
public deploy(platform: string): IFuture<void> {
195+
return (() => {
196+
platform = platform.toLowerCase();
197+
198+
this.validatePlatformInstalled(platform);
199+
200+
var platformData = this.$platformsData.getPlatformData(platform);
201+
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+
}
221+
222+
var packageFile = packages[0].pkg;
223+
this.$logger.out("Using ", packageFile);
224+
225+
this.$devicesServices.initialize(platform, options.device).wait();
226+
var action = (device: Mobile.IDevice): IFuture<void> => { return device.deploy(packageFile, this.$projectData.projectId); };
227+
this.$devicesServices.execute(action).wait();
228+
229+
}).future<void>()();
230+
}
231+
193232
private validatePlatform(platform: string): void {
194233
if(!platform) {
195234
this.$errors.fail("No platform specified.")
@@ -245,5 +284,20 @@ export class PlatformService implements IPlatformService {
245284
}
246285
return undefined;
247286
}
287+
288+
private processPlatformSpecificFiles( platform: string, files: string[]): IFuture<void> {
289+
// Renames the files that have `platform` as substring and removes the files from other platform
290+
return (() => {
291+
_.each(files, fileName => {
292+
var platformInfo = PlatformService.parsePlatformSpecificFileName(path.basename(fileName), this.$platformsData.platformsNames);
293+
var shouldExcludeFile = platformInfo && platformInfo.platform !== platform;
294+
if (shouldExcludeFile) {
295+
this.$fs.deleteFile(fileName).wait();
296+
} else if (platformInfo && platformInfo.onDeviceName) {
297+
this.$fs.rename(fileName, path.join(path.dirname(fileName), platformInfo.onDeviceName)).wait();
298+
}
299+
});
300+
}).future<void>()();
301+
}
248302
}
249303
$injector.register("platformService", PlatformService);

0 commit comments

Comments
 (0)