Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 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
8 changes: 8 additions & 0 deletions lib/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@ require("./common/bootstrap");
$injector.require("nativescript-cli", "./nativescript-cli");

$injector.require("projectService", "./services/project-service");
$injector.require("androidProjectService", "./services/project-service");
$injector.require("iOSProjectService", "./services/project-service");
$injector.require("projectTemplatesService", "./services/project-templates-service");
$injector.require("platformService", "./services/platform-service");

$injector.requireCommand("create", "./commands/create-project-command");
$injector.requireCommand("platform|*list", "./commands/platform-command");
$injector.requireCommand("platform|add", "./commands/platform-command");
$injector.requireCommand("run", "./commands/run-command");
$injector.requireCommand("prepare", "./commands/run-command");
$injector.requireCommand("build", "./commands/run-command");

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

export class ListPlatformsCommand implements ICommand {
constructor(private $platformService: IPlatformService,
private $logger: ILogger) { }

execute(args: string[]): IFuture<void> {
return (() => {
var availablePlatforms = this.$platformService.getAvailablePlatforms().wait();
this.$logger.out("Available platforms: %s", helpers.formatListOfNames(availablePlatforms));

var installedPlatforms = this.$platformService.getInstalledPlatforms().wait();
this.$logger.out("Installed platforms %s", helpers.formatListOfNames(installedPlatforms));
}).future<void>()();
}
}
$injector.registerCommand("platform|*list", ListPlatformsCommand);

export class AddPlatformCommand implements ICommand {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should't this be in a separate file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? Javascript is module oriented and I think we should combine all platform releated commands into one file :)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you put yourself in the foots of the JS VM and the context of CLI it does not make sense because we will only every execute a single command from the command line. There is no need to parse the whole file just to execute a portion of it 😄

constructor(private $platformService: IPlatformService) { }

execute(args: string[]): IFuture<void> {
return (() => {
this.$platformService.addPlatforms(args).wait();
}).future<void>()();
}
}
$injector.registerCommand("platform|add", AddPlatformCommand);
34 changes: 34 additions & 0 deletions lib/commands/run-command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
///<reference path="../.d.ts"/>

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

execute(args: string[]): IFuture<void> {
return (() => {
this.$platformService.runPlatform(args[0]).wait();
}).future<void>()();
}
}
$injector.registerCommand("run", RunCommand);

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

execute(args: string[]): IFuture<void> {
return (() => {
this.$platformService.preparePlatform(args[0]).wait();
}).future<void>()();
}
}
$injector.registerCommand("prepare", PrepareCommand);

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

execute(args: string[]): IFuture<void> {
return (() => {
this.$platformService.buildPlatform(args[0]).wait();
}).future<void>()();
}
}
$injector.registerCommand("build", BuildCommand);
2 changes: 1 addition & 1 deletion lib/common
12 changes: 12 additions & 0 deletions lib/definitions/platform.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
interface IPlatformService {
addPlatforms(platforms: string[]): IFuture<void>;
getInstalledPlatforms(): IFuture<string[]>;
getAvailablePlatforms(): IFuture<string[]>;
runPlatform(platform: string): IFuture<void>;
preparePlatform(platform: string): IFuture<void>;
buildPlatform(platform: string): IFuture<void>;
}

interface IPlatformCapabilities {
targetedOS?: string[];
}
24 changes: 24 additions & 0 deletions lib/definitions/project.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,31 @@
interface IProjectService {
createProject(projectName: string, projectId: string): IFuture<void>;
createPlatformSpecificProject(platform: string): IFuture<void>;
prepareProject(platform: string): IFuture<void>;
buildProject(platform: string): IFuture<void>;
ensureProject(): void;
projectData: IProjectData;
}

interface IAndroidProjectService {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need separate interfaces for Android and iOS or just a common IPlatformProjectService?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a common is better :)

createProject(projectData: IProjectData): IFuture<void>;
prepareProject(projectData: IProjectData): IFuture<void>;
buildProject(projectData: IProjectData): IFuture<void>;
}

interface IiOSProjectService {
createProject(projectData: IProjectData): IFuture<void>;
}

interface IProjectData {
projectDir: string;
platformsDir: string;
projectFilePath: string;
projectId?: string;
projectName?: string;
}

interface IProjectTemplatesService {
defaultTemplatePath: IFuture<string>;
androidFrameworkPath: IFuture<string>;
}
1 change: 1 addition & 0 deletions lib/definitions/shelljs.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ declare module "shelljs" {
function cp(arg: string, sourcePath: string, destinationPath: string): void;
function sed(arg: string, oldValue: any, newValue: string, filePath: string): void;
function mv(source: string[], destination: string);
function grep(what: any, where: string): any;
}
8 changes: 4 additions & 4 deletions lib/nativescript-cli.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
///<reference path=".d.ts"/>
"use strict";

import Fiber = require("fibers");
import Future = require("fibers/future");
import path = require("path");

require("./common/extensions");
require("./bootstrap");
require("./options");

import errors = require("./common/errors");
errors.installUncaughtExceptionListener();

$injector.register("config", {"CI_LOGGER": false});
$injector.register("config", {"CI_LOGGER": false, PROJECT_FILE_NAME: ".tnsproject", "DEBUG": true});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't ship with DEBUG: true. I suggest you use an environment variable for the purpose, e.g. set NATIVESCRIPT_DEBUG=true before running tns commands.


var dispatcher = $injector.resolve("dispatcher");
dispatcher.runMainFiber();
dispatcher.runMainFiber();
2 changes: 1 addition & 1 deletion lib/node-package-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ export class NodePackageManager implements INodePackageManager {
return future;
}
}
$injector.register("npm", NodePackageManager);
$injector.register("npm", NodePackageManager);
127 changes: 127 additions & 0 deletions lib/services/platform-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
///<reference path="../.d.ts"/>

import path = require("path");
import helpers = require("./../common/helpers");

export class PlatformService implements IPlatformService {
constructor(private $errors: IErrors,
private $fs: IFileSystem,
private $projectService: IProjectService) { }

private platformCapabilities: { [key: string]: IPlatformCapabilities } = {
ios: {
targetedOS: ['darwin']
},
android: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing OS'es?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

targetedOS is not obligatory property and when it is not specified that means that the platform is targeted for all supported os'es :)

}
};

public getCapabilities(platform: string): IPlatformCapabilities {
return this.platformCapabilities[platform];
}

public addPlatforms(platforms: string[]): IFuture<void> {
return (() => {
this.$projectService.ensureProject();

if(!platforms || platforms.length === 0) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check should be the first one to do in this function.

this.$errors.fail("No platform specified. Please specify a platform to add");
}

var platformsDir = this.$projectService.projectData.platformsDir;
if(!this.$fs.exists(platformsDir).wait()) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not extract an ensureDirectoryExists method in $fs?

this.$fs.createDirectory(platformsDir).wait();
}

_.each(platforms, platform => {
this.addPlatform(platform.toLowerCase()).wait();
});

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

private addPlatform(platform: string): IFuture<void> {
return(() => {
platform = platform.split("@")[0];
var platformPath = path.join(this.$projectService.projectData.platformsDir, platform);

// TODO: Check for version compatability if the platform is in format platform@version. This should be done in PR for semanting versioning

this.validatePlatform(platform);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check can be done on the 2nd line of this method.


if (this.$fs.exists(platformPath).wait()) {
this.$errors.fail("Platform %s already added", platform);
}

// Copy platform specific files in platforms dir
this.$projectService.createPlatformSpecificProject(platform).wait();

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

public getInstalledPlatforms(): IFuture<string[]> {
return(() => {
if(!this.$fs.exists(this.$projectService.projectData.platformsDir).wait()) {
return [];
}

var subDirs = this.$fs.readDirectory(this.$projectService.projectData.platformsDir).wait();
return _.filter(subDirs, p => { return Object.keys(this.platformCapabilities).indexOf(p) > -1; });
}).future<string[]>()();
}

public getAvailablePlatforms(): IFuture<string[]> {
return (() => {
var installedPlatforms = this.getInstalledPlatforms().wait();
return _.filter(_.keys(this.platformCapabilities), p => {
return installedPlatforms.indexOf(p) < 0 && this.isPlatformSupportedForOS(p); // Only those not already installed
});
}).future<string[]>()();
}

public runPlatform(platform: string): IFuture<void> {
return (() => {

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

public preparePlatform(platform: string): IFuture<void> {
return (() => {
this.validatePlatform(platform);

this.$projectService.prepareProject(platform).wait();
}).future<void>()();
}

public buildPlatform(platform: string): IFuture<void> {
return (() => {
this.$projectService.buildProject(platform);
}).future<void>()();
}

private validatePlatform(platform): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

: string

if (!this.isValidPlatform(platform)) {
this.$errors.fail("Invalid platform %s. Valid platforms are %s.", platform, helpers.formatListOfNames(_.keys(this.platformCapabilities)));
}

if (!this.isPlatformSupportedForOS(platform)) {
this.$errors.fail("Applications for platform %s can not be built on this OS - %s", platform, process.platform);
}
}

private isValidPlatform(platform: string) {
return this.platformCapabilities[platform];
}

private isPlatformSupportedForOS(platform: string): boolean {
var platformCapabilities = this.getCapabilities(platform);
var targetedOS = platformCapabilities.targetedOS;

if(!targetedOS || targetedOS.indexOf("*") >= 0 || targetedOS.indexOf(process.platform) >= 0) {
return true;
}

return false;
}
}
$injector.register("platformService", PlatformService);
Loading