Skip to content

Deploy to connected device #37

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 19, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ $injector.requireCommand("platform|remove", "./commands/remove-platform");
$injector.requireCommand("run", "./commands/run");
$injector.requireCommand("prepare", "./commands/prepare");
$injector.requireCommand("build", "./commands/build");
$injector.requireCommand("deploy", "./commands/deploy");

$injector.require("npm", "./node-package-manager");
$injector.require("config", "./config");
12 changes: 12 additions & 0 deletions lib/commands/deploy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
///<reference path="../.d.ts"/>

export class DeployCommand implements ICommand {
constructor(private $platformService: IPlatformService) { }

execute(args: string[]): IFuture<void> {
return (() => {
this.$platformService.deploy(args[0]).wait();
}).future<void>()();
}
}
$injector.registerCommand("deploy", DeployCommand);
8 changes: 7 additions & 1 deletion lib/config.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
///<reference path=".d.ts"/>

import path = require("path");
import util = require("util");

export class StaticConfig implements IStaticConfig {
public PROJECT_FILE_NAME = ".tnsproject";
public CLIENT_NAME = "tns";
public ANALYTICS_API_KEY = "5752dabccfc54c4ab82aea9626b7338e";
public TRACK_FEATURE_USAGE_SETTING_NAME = "TrackFeatureUsage";
public ANALYTICS_INSTALLATION_ID_SETTING_NAME = "AnalyticsInstallationID";
public START_PACKAGE_ACTIVITY_NAME = "com.tns.NativeScriptActivity";

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

public get helpTextPath() {
public get helpTextPath(): string {
return path.join(__dirname, "../resources/help.txt");
}

public get adbFilePath(): string {
return path.join(__dirname, util.format("../resources/platform-tools/android/%s/adb", process.platform));
}
}
$injector.register("staticConfig", StaticConfig);
1 change: 1 addition & 0 deletions lib/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
///<reference path=".d.ts"/>

export var APP_FOLDER_NAME = "app";
export var TNS_MODULES_FOLDER_NAME = "tns_modules";
export var DEFAULT_PROJECT_ID = "com.telerik.tns.HelloWorld";
export var DEFAULT_PROJECT_NAME = "HelloNativescript";
export var APP_RESOURCES_FOLDER_NAME = "App_Resources";
Expand Down
5 changes: 4 additions & 1 deletion lib/definitions/platform.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ interface IPlatformService {
addPlatforms(platforms: string[]): IFuture<void>;
getInstalledPlatforms(): IFuture<string[]>;
getAvailablePlatforms(): IFuture<string[]>;
removePlatforms(platforms: string[]): IFuture<void>;
runPlatform(platform: string): IFuture<void>;
preparePlatform(platform: string): IFuture<void>;
buildPlatform(platform: string): IFuture<void>;
removePlatforms(platforms: string[]): IFuture<void>;
deploy(platform: string): IFuture<void>;
}

interface IPlatformData {
frameworkPackageName: string;
platformProjectService: IPlatformProjectService;
projectRoot: string;
normalizedPlatformName: string;
buildOutputPath: string;
validPackageNames: string[];
targetedOS?: string[];
}

Expand Down
2 changes: 1 addition & 1 deletion lib/nativescript-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ $injector.register("config", {
DEBUG: process.env.NATIVESCRIPT_DEBUG,
version: require("../package.json").version,
helpTextPath: path.join(__dirname, "../resources/help.txt"),
client: "tns"
client: "nativescript"
});

var dispatcher = $injector.resolve("dispatcher");
Expand Down
20 changes: 13 additions & 7 deletions lib/services/android-project-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import path = require("path");
import shell = require("shelljs");
import util = require("util");
import options = require("./../options");
import helpers = require("./../common/helpers");
import constants = require("./../constants");
import hostInfo = require("../common/host-info");

class AndroidProjectService implements IPlatformProjectService {
private targetApi: string;
Expand All @@ -21,7 +21,12 @@ class AndroidProjectService implements IPlatformProjectService {
frameworkPackageName: "tns-android",
normalizedPlatformName: "Android",
platformProjectService: this,
projectRoot: path.join(this.$projectData.platformsDir, "android")
projectRoot: path.join(this.$projectData.platformsDir, "android"),
buildOutputPath: path.join(this.$projectData.platformsDir, "android", "bin"),
validPackageNames: [
util.format("%s-%s.%s", this.$projectData.projectName, "debug", "apk"),
util.format("%s-%s.%s", this.$projectData.projectName, "release", "apk")
]
};
}

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

shell.cp("-r", appSourceDirectory, assetsDirectory);
shell.cp("-r", path.join(appSourceDirectory, "*"), assetsDirectory);

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

return path.join(assetsDirectory, constants.APP_FOLDER_NAME);
return assetsDirectory;

}).future<string>()();
}
Expand All @@ -106,7 +111,7 @@ class AndroidProjectService implements IPlatformProjectService {
}

private spawn(command: string, args: string[]): IFuture<void> {
if (helpers.isWindows()) {
if (hostInfo.isWindows()) {
args.unshift('/s', '/c', command);
command = 'cmd';
}
Expand All @@ -124,7 +129,8 @@ class AndroidProjectService implements IPlatformProjectService {
return (() => {
var args = [
"--path", projectPath,
"--target", targetApi
"--target", targetApi,
"--name", this.$projectData.projectName
];

this.spawn("android", ['update', 'project'].concat(args)).wait();
Expand Down
23 changes: 20 additions & 3 deletions lib/services/ios-project-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ class IOSProjectService implements IPlatformProjectService {
normalizedPlatformName: "iOS",
platformProjectService: this,
projectRoot: path.join(this.$projectData.platformsDir, "ios"),
buildOutputPath: path.join(this.$projectData.platformsDir, "ios", "build", "device"),
validPackageNames: [
this.$projectData.projectName + ".ipa"
],
targetedOS: ['darwin']
};
}
Expand Down Expand Up @@ -76,9 +80,10 @@ class IOSProjectService implements IPlatformProjectService {
return (() => {
var appSourceDirectory = path.join(this.$projectData.projectDir, constants.APP_FOLDER_NAME);
var appDestinationDirectory = path.join(platformData.projectRoot, this.$projectData.projectName);
shell.cp("-r", appSourceDirectory, appDestinationDirectory);

return path.join(appDestinationDirectory, constants.APP_FOLDER_NAME);
shell.cp("-r", path.join(appSourceDirectory, "*"), appDestinationDirectory);

return appDestinationDirectory;
}).future<string>()();
}

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

var buildOutputPath = path.join(projectRoot, "build", options.device ? "device" : "emulator");

// Produce ipa file
var xcrunArgs = [
"-sdk", "iphoneos",
"PackageApplication",
"-v", path.join(buildOutputPath, this.$projectData.projectName + ".app"),
"-o", path.join(buildOutputPath, this.$projectData.projectName + ".ipa")
];

var childProcess = this.$childProcess.spawn("xcrun", xcrunArgs, {cwd: options, stdio: 'inherit'});
this.$fs.futureFromEvent(childProcess, "exit").wait();
}).future<void>()();
}

Expand Down
76 changes: 65 additions & 11 deletions lib/services/platform-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import shell = require("shelljs");
import util = require("util");
import constants = require("./../constants");
import helpers = require("./../common/helpers");
import options = require("./../options");

class PlatformsData implements IPlatformsData {
private platformsData : { [index: string]: any } = {};
Expand Down Expand Up @@ -34,7 +35,8 @@ export class PlatformService implements IPlatformService {
private $logger: ILogger,
private $npm: INodePackageManager,
private $projectData: IProjectData,
private $platformsData: IPlatformsData) { }
private $platformsData: IPlatformsData,
private $devicesServices: Mobile.IDevicesServices) { }

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

var appFilesLocation = platformProjectService.prepareProject(platformData).wait();
var files = helpers.enumerateFilesInDirectorySync(appFilesLocation);

_.each(files, fileName => {
var platformInfo = PlatformService.parsePlatformSpecificFileName(path.basename(fileName), this.$platformsData.platformsNames);
var shouldExcludeFile = platformInfo && platformInfo.platform !== platform;
if (shouldExcludeFile) {
this.$fs.deleteFile(fileName).wait();
} else if (platformInfo && platformInfo.onDeviceName) {
this.$fs.rename(fileName, path.join(path.dirname(fileName), platformInfo.onDeviceName)).wait();
}
});
this.processPlatformSpecificFiles(platform, helpers.enumerateFilesInDirectorySync(path.join(appFilesLocation, constants.APP_FOLDER_NAME))).wait();
this.processPlatformSpecificFiles(platform, helpers.enumerateFilesInDirectorySync(path.join(appFilesLocation, constants.TNS_MODULES_FOLDER_NAME))).wait();

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

this.preparePlatform(platform).wait();

// We need to set device option here
var cachedDeviceOption = options.device;
options.device = true;
this.buildPlatform(platform).wait();
options.device = cachedDeviceOption;

this.deploy(platform).wait();
}).future<void>()();
}

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

public deploy(platform: string): IFuture<void> {
return (() => {
platform = platform.toLowerCase();

this.validatePlatformInstalled(platform);

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

// Get latest package that is produced from build
var candidates = this.$fs.readDirectory(platformData.buildOutputPath).wait();
var packages = _.filter(candidates, candidate => {
return _.contains(platformData.validPackageNames, candidate);
}).map(currentPackage => {
currentPackage = path.join(platformData.buildOutputPath, currentPackage);

return {
pkg: currentPackage,
time: this.$fs.getFsStats(currentPackage).wait().mtime
};
});

packages = _.sortBy(packages, pkg => pkg.time ).reverse(); // We need to reverse because sortBy always sorts in ascending order

if(packages.length === 0) {
var packageExtName = path.extname(platformData.validPackageNames[0]);
this.$errors.fail("No %s found in %s directory", packageExtName, platformData.buildOutputPath)
}

var packageFile = packages[0].pkg;
this.$logger.out("Using ", packageFile);

this.$devicesServices.initialize(platform, options.device).wait();
var action = (device: Mobile.IDevice): IFuture<void> => { return device.deploy(packageFile, this.$projectData.projectId); };
this.$devicesServices.execute(action).wait();

}).future<void>()();
}

private validatePlatform(platform: string): void {
if(!platform) {
this.$errors.fail("No platform specified.")
Expand Down Expand Up @@ -245,5 +284,20 @@ export class PlatformService implements IPlatformService {
}
return undefined;
}

private processPlatformSpecificFiles( platform: string, files: string[]): IFuture<void> {
// Renames the files that have `platform` as substring and removes the files from other platform
return (() => {
_.each(files, fileName => {
var platformInfo = PlatformService.parsePlatformSpecificFileName(path.basename(fileName), this.$platformsData.platformsNames);
var shouldExcludeFile = platformInfo && platformInfo.platform !== platform;
if (shouldExcludeFile) {
this.$fs.deleteFile(fileName).wait();
} else if (platformInfo && platformInfo.onDeviceName) {
this.$fs.rename(fileName, path.join(path.dirname(fileName), platformInfo.onDeviceName)).wait();
}
});
}).future<void>()();
}
}
$injector.register("platformService", PlatformService);
7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@
"mobile"
],
"dependencies": {
"bufferpack": "0.0.6",
"byline": "4.1.1",
"colors": "0.6.2",
"ffi": "https://github.com/icenium/node-ffi/tarball/master",
"fibers": "https://github.com/icenium/node-fibers/tarball/master",
"filesize": "2.0.3",
"log4js": "0.6.9",
Expand All @@ -31,13 +34,17 @@
"node-uuid": "1.4.1",
"npm": "1.4.10",
"osenv": "0.1.0",
"plistlib": "0.2.1",
"progress-stream": "0.5.0",
"prompt": "https://github.com/Icenium/prompt/tarball/master",
"properties-parser": "0.2.3",
"ref": "https://github.com/icenium/ref/tarball/master",
"ref-struct": "0.0.5",
"rimraf": "2.2.6",
"semver": "3.0.1",
"shelljs": "0.3.0",
"tabtab": "https://github.com/tailsu/node-tabtab/tarball/master",
"temp": "0.8.1",
"underscore": "1.5.2",
"unzip": "0.1.9",
"watchr": "2.4.11",
Expand Down
13 changes: 13 additions & 0 deletions resources/help.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ General commands:
prepare Copies cross-platform content to the subdirectory for the selected target platform.
This lets you build the project with the SDK for the selected platform and deploy it on device.
build Builds the project for the selected target platform and produces an application package.
deploy Deploys the project to a connected device.
run Runs your project on a connected device. This is shorthand for prepare, build, and deploy.
feature-usage-tracking Configures anonymous feature usage tracking.

Expand Down Expand Up @@ -145,6 +146,18 @@ in the project.

--[/]--

--[deploy]--
Usage:
$ tns deploy <Platform> [--device <Device ID>]

Platform-specific usages:
$ tns deploy android [--device <Device ID>]
$ tns deploy ios [--device <Device ID>]

Deploys the project to a connected device.

--[/]--

--[run]--

Usage:
Expand Down
Loading