Skip to content

Commit d3f9dae

Browse files
Merge pull request #572 from NativeScript/vladimirov/merge-1.1.1
Merge changes for 1.1.1 release in master
2 parents af40a72 + 523bab0 commit d3f9dae

File tree

12 files changed

+424
-39
lines changed

12 files changed

+424
-39
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
NativeScript CLI Changelog
22
================
33

4+
1.1.1 (2015, June 17)
5+
==
6+
7+
### New
8+
* [Implemented #551](https://github.com/NativeScript/nativescript-cli/issues/551): Add support for Android 5.1.1 (API Level 22). In case you have this SDK installed, it will be used as default when using `tns platform add android`.
9+
* [Implemented #552](https://github.com/NativeScript/nativescript-cli/issues/552): Add `--sdk` option to specify Android Target SDK. You can use `tns platform add android --sdk <API_LEVEL>` to target specific SDK.
10+
11+
### Fixed
12+
* [Fixed #555](https://github.com/NativeScript/nativescript-cli/issues/555): Merging plugin's platform specific XMLs with project's platform specific XMLs is not working correctly in some cases.
13+
* [Fixed #567](https://github.com/NativeScript/nativescript-cli/issues/567): Npm support does not work.
14+
* [Fixed #569](https://github.com/NativeScript/nativescript-cli/issues/569): On some Windows systems, installation is showing errors in the output.
15+
416
1.1.0 (2015, June 10)
517
==
618

docs/man_pages/project/configuration/platform-add.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ platform add
33

44
Usage | Synopsis
55
------|-------
6-
Android latest runtime | `$ tns platform add android [--frameworkPath <File Path>] [--symlink]`
7-
Android selected runtime | `$ tns platform add android[@<Version>] [--frameworkPath <File Path>] [--symlink]`
6+
Android latest runtime | `$ tns platform add android [--frameworkPath <File Path>] [--symlink] [--sdk <target sdk>]`
7+
Android selected runtime | `$ tns platform add android[@<Version>] [--frameworkPath <File Path>] [--symlink] [--sdk <target sdk>]`
88
<% if (isMacOS) { %>iOS latest runtime | `$ tns platform add ios [--frameworkPath <File Path>] [--symlink]`
99
iOS selected runtime | `$ tns platform add ios[@<Version>] [--frameworkPath <File Path>] [--symlink]`<% } %>
1010

@@ -13,6 +13,7 @@ Configures the current project to target the selected platform. <% if(isHtml) {
1313
### Options
1414
* `--frameworkPath` - Sets the path to a NativeScript runtime for the specified platform that you want to use instead of the default runtime. If `--symlink` is specified, `<File Path>` must point to directory in which the runtime is already extracted. If `--symlink` is not specified, `<File Path>` must point to a valid npm package.
1515
* `--symlink` - Creates a symlink to a NativeScript runtime for the specified platform that you want to use instead of the default runtime. If `--frameworkPath` is specified, creates a symlink to the specified directory. If `--frameworkPath` is not specified, creates a symlink to platform runtime installed with your current version of NativeScript.
16+
* `--sdk` - Sets the Android target SDK. The value should be a valid Android API Level, for example 17, 19, MNC.
1617

1718
### Attributes
1819
* `<File Path>` is the complete path to a valid npm package or a directory that contains a NativeScript runtime for the selected platform.

lib/declarations.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,5 @@ interface IOptions extends ICommonOptions {
6262
keyStorePassword: string;
6363
keyStoreAlias: string;
6464
keyStoreAliasPassword: string;
65+
sdk: string;
6566
}

lib/definitions/platform.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ interface IPlatformData {
3636
targetedOS?: string[];
3737
configurationFileName?: string;
3838
configurationFilePath?: string;
39+
mergeXmlConfig?: any[];
3940
}
4041

4142
interface IPlatformsData {

lib/options.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ export class Options extends commonOptionsLibPath.OptionsBase {
2424
keyStorePath: { type: OptionType.String },
2525
keyStorePassword: { type: OptionType.String,},
2626
keyStoreAlias: { type: OptionType.String },
27-
keyStoreAliasPassword: { type: OptionType.String }
27+
keyStoreAliasPassword: { type: OptionType.String },
28+
sdk: { type: OptionType.String }
2829
},
2930
path.join($hostInfo.isWindows ? process.env.LocalAppData : path.join(osenv.home(), ".local/share"), ".nativescript-cli"),
3031
$errors, $staticConfig);

lib/services/android-project-service.ts

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import fs = require("fs");
1010
import os = require("os");
1111

1212
class AndroidProjectService implements IPlatformProjectService {
13-
private SUPPORTED_TARGETS = ["android-17", "android-18", "android-19", "android-21"]; // forbidden for now: "android-MNC"
13+
private static MIN_SUPPORTED_VERSION = 17;
14+
private SUPPORTED_TARGETS = ["android-17", "android-18", "android-19", "android-21", "android-22"]; // forbidden for now: "android-MNC"
15+
private static ANDROID_TARGET_PREFIX = "android";
1416
private static RES_DIRNAME = "res";
1517
private static VALUES_DIRNAME = "values";
1618
private static VALUES_VERSION_DIRNAME_PREFIX = AndroidProjectService.VALUES_DIRNAME + "-v";
@@ -48,7 +50,8 @@ class AndroidProjectService implements IPlatformProjectService {
4850
],
4951
frameworkFilesExtensions: [".jar", ".dat", ".so"],
5052
configurationFileName: "AndroidManifest.xml",
51-
configurationFilePath: path.join(this.$projectData.platformsDir, "android", "AndroidManifest.xml")
53+
configurationFilePath: path.join(this.$projectData.platformsDir, "android", "AndroidManifest.xml"),
54+
mergeXmlConfig: [{ "nodename": "manifest", "attrname": "*" }]
5255
};
5356
}
5457

@@ -67,7 +70,9 @@ class AndroidProjectService implements IPlatformProjectService {
6770
public createProject(projectRoot: string, frameworkDir: string): IFuture<void> {
6871
return (() => {
6972
this.$fs.ensureDirectoryExists(projectRoot).wait();
70-
let newTarget = this.getLatestValidAndroidTarget(frameworkDir).wait();
73+
74+
let newTarget = this.getAndroidTarget(frameworkDir).wait();
75+
this.$logger.trace(`Using Android SDK '${newTarget}'.`);
7176
let versionNumber = _.last(newTarget.split("-"));
7277
if(this.$options.symlink) {
7378
this.copyResValues(projectRoot, frameworkDir, versionNumber).wait();
@@ -101,8 +106,22 @@ class AndroidProjectService implements IPlatformProjectService {
101106
this.$fs.createDirectory(resDestinationDir).wait();
102107
let versionDirName = AndroidProjectService.VALUES_VERSION_DIRNAME_PREFIX + versionNumber;
103108
let directoriesToCopy = [AndroidProjectService.VALUES_DIRNAME];
104-
if(this.$fs.exists(path.join(resSourceDir, versionDirName)).wait()) {
105-
directoriesToCopy.push(versionDirName);
109+
let directoriesInResFolder = this.$fs.readDirectory(resSourceDir).wait();
110+
let integerFrameworkVersion = parseInt(versionNumber);
111+
let versionDir = _.find(directoriesInResFolder, dir => dir === versionDirName) ||
112+
_(directoriesInResFolder)
113+
.map(dir => {
114+
return {
115+
dirName: dir,
116+
sdkNum: parseInt(dir.substr(AndroidProjectService.VALUES_VERSION_DIRNAME_PREFIX.length))
117+
}
118+
})
119+
.filter(dir => dir.dirName.match(AndroidProjectService.VALUES_VERSION_DIRNAME_PREFIX) && dir.sdkNum && (!integerFrameworkVersion || (integerFrameworkVersion >= dir.sdkNum)))
120+
.max(dir => dir.sdkNum)
121+
.dirName;
122+
123+
if(versionDir) {
124+
directoriesToCopy.push(versionDir);
106125
}
107126

108127
this.copy(resDestinationDir, resSourceDir, directoriesToCopy.join(" "), "-R").wait();
@@ -331,17 +350,37 @@ class AndroidProjectService implements IPlatformProjectService {
331350
}
332351
}
333352

353+
private getAndroidTarget(frameworkDir: string): IFuture<string> {
354+
return ((): string => {
355+
let newTarget = this.$options.sdk ? `${AndroidProjectService.ANDROID_TARGET_PREFIX}-${this.$options.sdk}` : this.getLatestValidAndroidTarget(frameworkDir).wait();
356+
if(!_.contains(this.SUPPORTED_TARGETS, newTarget)) {
357+
let versionNumber = parseInt(_.last(newTarget.split("-")));
358+
if(versionNumber && (versionNumber < AndroidProjectService.MIN_SUPPORTED_VERSION)) {
359+
this.$errors.failWithoutHelp(`The selected target SDK ${newTarget} is not supported. You should target at least ${AndroidProjectService.MIN_SUPPORTED_VERSION}.`);
360+
}
361+
362+
if(!_.contains(this.getInstalledTargets().wait(), newTarget)) {
363+
this.$errors.failWithoutHelp(`You have selected to use ${newTarget}, but it is not currently installed.`+
364+
' Run \"android\" from your command-line to install/update any missing SDKs or tools.');
365+
}
366+
this.$logger.warn(`The selected Android target '${newTarget}' is not verified as supported. Some functionality may not work as expected.`);
367+
}
368+
369+
return newTarget;
370+
}).future<string>()();
371+
}
372+
334373
private getLatestValidAndroidTarget(frameworkDir: string): IFuture<string> {
335374
return (() => {
336375
let validTarget = this.getTarget(frameworkDir).wait();
337376
let installedTargets = this.getInstalledTargets().wait();
338377

339378
// adjust to the latest available version
340-
var newTarget = _(this.SUPPORTED_TARGETS).sort().findLast(supportedTarget => _.contains(installedTargets, supportedTarget));
379+
var newTarget = _(this.SUPPORTED_TARGETS).sort().findLast(supportedTarget => _.contains(installedTargets, supportedTarget));
341380
if (!newTarget) {
342-
this.$errors.fail("Please install Android target %s. Make sure you have the latest Android tools installed as well." +
343-
" Run \"android\" from your command-line to install/update any missing SDKs or tools.",
344-
validTarget.split('-')[1]);
381+
this.$errors.failWithoutHelp(`Could not find supported Android target. Please install one of the following: ${this.SUPPORTED_TARGETS.join(", ")}.` +
382+
" Make sure you have the latest Android tools installed as well." +
383+
' Run "android" from your command-line to install/update any missing SDKs or tools.')
345384
}
346385

347386
return newTarget;

lib/services/plugins-service.ts

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import semver = require("semver");
66
import Future = require("fibers/future");
77
import constants = require("./../constants");
88
let xmlmerge = require("xmlmerge-js");
9+
let DOMParser = require('xmldom').DOMParser;
910

1011
export class PluginsService implements IPluginsService {
1112
private static INSTALL_COMMAND_NAME = "install";
@@ -60,40 +61,52 @@ export class PluginsService implements IPluginsService {
6061
public prepare(pluginData: IPluginData): IFuture<void> {
6162
return (() => {
6263
let action = (pluginDestinationPath: string, platform: string, platformData: IPlatformData) => {
63-
let skipExecution = false;
6464
// Process .js files
6565
let installedFrameworkVersion = this.getInstalledFrameworkVersion(platform).wait();
6666
let pluginPlatformsData = pluginData.platformsData;
6767
if(pluginPlatformsData) {
6868
let pluginVersion = (<any>pluginPlatformsData)[platform];
69+
if(!pluginVersion) {
70+
this.$logger.warn(`${pluginData.name} is not supported for ${platform}.`);
71+
return;
72+
}
73+
6974
if(semver.gt(pluginVersion, installedFrameworkVersion)) {
7075
this.$logger.warn(`${pluginData.name} ${pluginVersion} for ${platform} is not compatible with the currently installed framework version ${installedFrameworkVersion}.`);
71-
skipExecution = true;
76+
return;
7277
}
7378
}
79+
80+
this.$fs.ensureDirectoryExists(pluginDestinationPath).wait();
81+
shelljs.cp("-R", pluginData.fullPath, pluginDestinationPath);
82+
83+
let pluginPlatformsFolderPath = path.join(pluginDestinationPath, pluginData.name, "platforms", platform);
84+
let pluginConfigurationFilePath = path.join(pluginPlatformsFolderPath, platformData.configurationFileName);
85+
let configurationFilePath = platformData.configurationFilePath;
7486

75-
if(!skipExecution) {
76-
this.$fs.ensureDirectoryExists(pluginDestinationPath).wait();
77-
shelljs.cp("-R", pluginData.fullPath, pluginDestinationPath);
78-
79-
let pluginPlatformsFolderPath = path.join(pluginDestinationPath, pluginData.name, "platforms", platform);
80-
let pluginConfigurationFilePath = path.join(pluginPlatformsFolderPath, platformData.configurationFileName);
81-
if(this.$fs.exists(pluginConfigurationFilePath).wait()) {
82-
let pluginConfigurationFileContent = this.$fs.readText(pluginConfigurationFilePath).wait();
83-
let configurationFileContent = this.$fs.readText(platformData.configurationFilePath).wait();
84-
let resultXml = this.mergeXml(pluginConfigurationFileContent, configurationFileContent).wait();
85-
this.$fs.writeFile(platformData.configurationFilePath, resultXml).wait();
86-
}
87-
88-
if(this.$fs.exists(pluginPlatformsFolderPath).wait()) {
89-
shelljs.rm("-rf", pluginPlatformsFolderPath);
90-
}
87+
if(this.$fs.exists(pluginConfigurationFilePath).wait()) {
88+
// Validate plugin configuration file
89+
let pluginConfigurationFileContent = this.$fs.readText(pluginConfigurationFilePath).wait();
90+
this.validateXml(pluginConfigurationFileContent, pluginConfigurationFilePath);
9191

92-
// TODO: Add libraries
92+
// Validate configuration file
93+
let configurationFileContent = this.$fs.readText(configurationFilePath).wait();
94+
this.validateXml(configurationFileContent, configurationFilePath);
9395

94-
// Show message
95-
this.$logger.out(`Successfully prepared plugin ${pluginData.name} for ${platform}.`);
96+
// Merge xml
97+
let resultXml = this.mergeXml(configurationFileContent, pluginConfigurationFileContent, platformData.mergeXmlConfig || []).wait();
98+
this.validateXml(resultXml);
99+
this.$fs.writeFile(configurationFilePath, resultXml).wait();
96100
}
101+
102+
if(this.$fs.exists(pluginPlatformsFolderPath).wait()) {
103+
shelljs.rm("-rf", pluginPlatformsFolderPath);
104+
}
105+
106+
// TODO: Add libraries
107+
108+
// Show message
109+
this.$logger.out(`Successfully prepared plugin ${pluginData.name} for ${platform}.`);
97110
};
98111

99112
this.executeForAllInstalledPlatforms(action);
@@ -209,11 +222,11 @@ export class PluginsService implements IPluginsService {
209222
}).future<string>()();
210223
}
211224

212-
private mergeXml(xml1: string, xml2: string): IFuture<string> {
225+
private mergeXml(xml1: string, xml2: string, config: any[]): IFuture<string> {
213226
let future = new Future<string>();
214227

215228
try {
216-
xmlmerge.merge(xml1, xml2, "", (mergedXml: string) => {
229+
xmlmerge.merge(xml1, xml2, config, (mergedXml: string) => {
217230
future.return(mergedXml);
218231
});
219232
} catch(err) {
@@ -222,5 +235,16 @@ export class PluginsService implements IPluginsService {
222235

223236
return future;
224237
}
238+
239+
private validateXml(xml: string, xmlFilePath?: string): void {
240+
let doc = new DOMParser({
241+
locator: {},
242+
errorHandler: (level: any, msg: string) => {
243+
let errorMessage = xmlFilePath ? `Invalid xml file ${xmlFilePath}.` : `Invalid xml ${xml}.`;
244+
this.$errors.fail(errorMessage + ` Additional technical information: ${msg}.` )
245+
}
246+
});
247+
doc.parseFromString(xml, 'text/xml');
248+
}
225249
}
226250
$injector.register("pluginsService", PluginsService);

lib/tools/broccoli/trees/node-modules-tree.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ let Funnel = require('broccoli-funnel');
66
import path = require("path");
77
import destCopy from '../node-modules-dest-copy';
88

9-
class NodeModulesTree implements INodeModulesTree {
9+
export class NodeModulesTree implements INodeModulesTree {
1010
public makeNodeModulesTree(absoluteOutputPath: string, projectDir: string): any {
11-
let nodeModulesFunnel = new Funnel(".", { include: [projectDir + "/node_modules/**"] });
11+
let nodeModulesFunnel = new Funnel(projectDir, { include: ["node_modules/**"] });
1212
let result = destCopy(nodeModulesFunnel, absoluteOutputPath, "node_modules", projectDir);
1313
return result;
1414
}

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "nativescript",
33
"preferGlobal": true,
4-
"version": "1.1.0",
4+
"version": "1.1.1",
55
"author": "Telerik <support@telerik.com>",
66
"description": "Command-line interface for building NativeScript projects",
77
"bin": {
@@ -28,6 +28,7 @@
2828
"broccoli": "0.16.2",
2929
"broccoli-funnel": "0.2.3",
3030
"bufferpack": "0.0.6",
31+
"bufferutil": "https://github.com/telerik/bufferutil/tarball/master",
3132
"byline": "4.1.1",
3233
"chalk": "1.0.0",
3334
"cli-table": "https://github.com/telerik/cli-table/tarball/master",
@@ -64,9 +65,11 @@
6465
"shelljs": "0.3.0",
6566
"tabtab": "https://github.com/Icenium/node-tabtab/tarball/master",
6667
"temp": "0.8.1",
68+
"utf-8-validate": "https://github.com/telerik/utf-8-validate/tarball/master",
6769
"winreg": "0.0.12",
6870
"ws": "0.7.1",
6971
"xcode": "https://github.com/NativeScript/node-xcode/archive/NativeScript-0.9.tar.gz",
72+
"xmldom": "0.1.19",
7073
"xmlhttprequest": "https://github.com/telerik/node-XMLHttpRequest/tarball/master",
7174
"xmlmerge-js": "0.2.4",
7275
"yargs": "1.2.2"

0 commit comments

Comments
 (0)