Skip to content

Commit a60eabd

Browse files
committed
Revert "Merge pull request #2209 from NativeScript/plamen5kov/remove_npm2_dependency"
This reverts commit 40566ce, reversing changes made to 0be61c8.
1 parent 40566ce commit a60eabd

21 files changed

+726
-447
lines changed

lib/constants.ts

+1-21
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,6 @@ export let TEST_RUNNER_NAME = "nativescript-unit-test-runner";
1616
export let LIVESYNC_EXCLUDED_FILE_PATTERNS = ["**/*.js.map", "**/*.ts"];
1717
export let XML_FILE_EXTENSION = ".xml";
1818

19-
export class PackageVersion {
20-
static NEXT = "next";
21-
static LATEST = "latest";
22-
}
23-
24-
export class SaveOptions {
25-
static PRODUCTION = "save";
26-
static DEV = "save-dev";
27-
static OPTIONAL = "save-optional";
28-
static EXACT = "save-exact";
29-
}
30-
3119
export class ReleaseType {
3220
static MAJOR = "major";
3321
static PREMAJOR = "premajor";
@@ -38,14 +26,6 @@ export class ReleaseType {
3826
static PRERELEASE = "prerelease";
3927
}
4028

41-
export let RESERVED_TEMPLATE_NAMES: IStringDictionary = {
42-
"default": "tns-template-hello-world",
43-
"tsc": "tns-template-hello-world-ts",
44-
"typescript": "tns-template-hello-world-ts",
45-
"ng": "tns-template-hello-world-ng",
46-
"angular": "tns-template-hello-world-ng"
47-
};
48-
4929
export class ITMSConstants {
5030
static ApplicationMetadataFile = "metadata.xml";
5131
static VerboseLoggingLevels = {
@@ -64,4 +44,4 @@ class ItunesConnectApplicationTypesClass implements IiTunesConnectApplicationTyp
6444
export let ItunesConnectApplicationTypes = new ItunesConnectApplicationTypesClass();
6545

6646
export let ANGULAR_NAME = "angular";
67-
export let TYPESCRIPT_NAME = "typescript";
47+
export let TYPESCRIPT_NAME = "TypeScript";

lib/declarations.ts

+14-7
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
11
interface INodePackageManager {
2+
getCache(): string;
3+
load(config?: any): IFuture<void>;
24
install(packageName: string, pathToSave: string, config?: any): IFuture<any>;
35
uninstall(packageName: string, config?: any, path?: string): IFuture<any>;
4-
view(packageName: string, config: any): IFuture<any>;
5-
search(filter: string[], config: any): IFuture<any>;
6+
cache(packageName: string, version: string, cache?: any): IFuture<IDependencyData>;
7+
cacheUnpack(packageName: string, version: string, unpackTarget?: string): IFuture<void>;
8+
view(packageName: string, propertyName: string): IFuture<any>;
9+
executeNpmCommand(npmCommandName: string, currentWorkingDirectory: string): IFuture<any>;
10+
search(filter: string[], silent: boolean): IFuture<any>;
611
}
712

813
interface INpmInstallationManager {
9-
install(packageName: string, packageDir: string, options?: INpmInstallOptions): IFuture<any>;
14+
getCacheRootPath(): string;
15+
addToCache(packageName: string, version: string): IFuture<any>;
16+
cacheUnpack(packageName: string, version: string, unpackTarget?: string): IFuture<void>;
17+
install(packageName: string, options?: INpmInstallOptions): IFuture<string>;
1018
getLatestVersion(packageName: string): IFuture<string>;
11-
getNextVersion(packageName: string): IFuture<string>;
1219
getLatestCompatibleVersion(packageName: string): IFuture<string>;
20+
getCachedPackagePath(packageName: string, version: string): string;
1321
}
1422

1523
interface INpmInstallOptions {
1624
pathToSave?: string;
1725
version?: string;
18-
dependencyType?: string;
1926
}
2027

2128
interface IDependencyData {
@@ -74,7 +81,7 @@ interface IOptions extends ICommonOptions {
7481
frameworkName: string;
7582
frameworkPath: string;
7683
frameworkVersion: string;
77-
ignoreScripts: boolean; //npm flag
84+
ignoreScripts: boolean;
7885
disableNpmInstall: boolean;
7986
ipa: string;
8087
keyStoreAlias: string;
@@ -88,7 +95,7 @@ interface IOptions extends ICommonOptions {
8895
bundle: boolean;
8996
platformTemplate: string;
9097
port: Number;
91-
production: boolean; //npm flag
98+
production: boolean;
9299
sdk: string;
93100
symlink: boolean;
94101
tnsModulesVersion: string;

lib/definitions/project.d.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ interface IProjectDataService {
2626
* Describes working with templates.
2727
*/
2828
interface IProjectTemplatesService {
29+
/**
30+
* Defines the path where unpacked default template can be found.
31+
*/
32+
defaultTemplatePath: IFuture<string>;
33+
2934
/**
3035
* Prepares template for project creation.
3136
* In case templateName is not provided, use defaultTemplatePath.
@@ -34,7 +39,7 @@ interface IProjectTemplatesService {
3439
* @param {string} templateName The name of the template.
3540
* @return {string} Path to the directory where extracted template can be found.
3641
*/
37-
prepareTemplate(templateName: string, projectDir: string): IFuture<string>;
42+
prepareTemplate(templateName: string): IFuture<string>;
3843
}
3944

4045
interface IPlatformProjectServiceBase {
@@ -72,7 +77,12 @@ interface IPlatformProjectService {
7277
prepareProject(): IFuture<void>;
7378
prepareAppResources(appResourcesDirectoryPath: string): IFuture<void>;
7479
isPlatformPrepared(projectRoot: string): IFuture<boolean>;
75-
canUpdatePlatform(newInstalledModuleDir: string): IFuture<boolean>;
80+
canUpdatePlatform(currentVersion: string, newVersion: string): IFuture<boolean>;
81+
/**
82+
* Provides a platform specific update logic for the specified runtime versions.
83+
* @return true in cases when the update procedure should continue.
84+
*/
85+
updatePlatform(currentVersion: string, newVersion: string, canUpdate: boolean, addPlatform?: Function, removePlatform?: (platforms: string[]) => IFuture<void>): IFuture<boolean>;
7686
preparePluginNativeCode(pluginData: IPluginData, options?: any): IFuture<void>;
7787
removePluginNativeCode(pluginData: IPluginData): IFuture<void>;
7888
afterPrepareAllPlugins(): IFuture<void>;

lib/node-package-manager.ts

+95-77
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import * as path from "path";
1+
import Future = require("fibers/future");
2+
import * as npm from "npm";
23

34
interface INpmOpts {
45
config?: any;
@@ -7,13 +8,35 @@ interface INpmOpts {
78
}
89

910
export class NodePackageManager implements INodePackageManager {
10-
constructor(private $fs: IFileSystem,
11-
private $hostInfo: IHostInfo,
12-
private $errors: IErrors,
13-
private $childProcess: IChildProcess,
11+
constructor(private $childProcess: IChildProcess,
1412
private $logger: ILogger,
1513
private $options: IOptions) { }
1614

15+
public getCache(): string {
16+
return npm.cache;
17+
}
18+
19+
public load(config?: any): IFuture<void> {
20+
if (npm.config.loaded) {
21+
let data = npm.config.sources.cli.data;
22+
Object.keys(data).forEach(k => delete data[k]);
23+
if (config) {
24+
_.assign(data, config);
25+
}
26+
return Future.fromResult();
27+
} else {
28+
let future = new Future<void>();
29+
npm.load(config, (err: Error) => {
30+
if (err) {
31+
future.throw(err);
32+
} else {
33+
future.return();
34+
}
35+
});
36+
return future;
37+
}
38+
}
39+
1740
public install(packageName: string, pathToSave: string, config?: any): IFuture<any> {
1841
return (() => {
1942
if (this.$options.disableNpmInstall) {
@@ -24,105 +47,100 @@ export class NodePackageManager implements INodePackageManager {
2447
config["ignore-scripts"] = true;
2548
}
2649

27-
let jsonContentBefore = this.$fs.readJson(path.join(pathToSave, "package.json")).wait();
28-
// let dependenciesBefore: Array<string> = [];
29-
let dependenciesBefore = _.keys(jsonContentBefore.dependencies).concat(_.keys(jsonContentBefore.devDependencies));
30-
31-
let flags = this.getFlagsString(config, true);
32-
let params = ["install"];
33-
if(packageName !== pathToSave) {
34-
params.push(packageName); //because npm install ${pwd} on mac tries to install itself as a dependency (windows and linux have no such issues)
35-
}
36-
params = params.concat(flags);
3750
try {
38-
this.$childProcess.spawnFromEvent(this.getNpmExecutableName(), params, "close", { cwd: pathToSave }).wait();
51+
return this.loadAndExecute("install", [pathToSave, packageName], { config: config }).wait();
3952
} catch (err) {
40-
if (err.message && err.message.indexOf("EPEERINVALID") !== -1) {
53+
if (err.code === "EPEERINVALID") {
4154
// Not installed peer dependencies are treated by npm 2 as errors, but npm 3 treats them as warnings.
4255
// We'll show them as warnings and let the user install them in case they are needed.
56+
// The strucutre of the error object in such case is:
57+
// { [Error: The package @angular/[email protected] does not satisfy its siblings' peerDependencies requirements!]
58+
// code: 'EPEERINVALID',
59+
// packageName: '@angular/core',
60+
// packageVersion: '2.1.0-beta.0',
61+
// peersDepending:
62+
// { '@angular/[email protected]': '2.1.0-beta.0',
63+
// '@angular/[email protected]': '2.1.0-beta.0',
64+
// '@angular/[email protected]': '2.1.0-beta.0',
65+
// '@angular/[email protected]': '2.1.0-beta.0',
66+
// '@angular/[email protected]': '2.1.0-beta.0',
67+
// '@angular/[email protected]': '2.1.0-beta.0',
68+
// '@angular/[email protected]': '2.1.0-beta.0',
69+
// '@angular/[email protected]': '2.1.0-beta.0',
70+
// '@ngrx/[email protected]': '^2.0.0',
71+
// '@ngrx/[email protected]': '^2.0.0',
72+
// '[email protected]': '~2.0.0' } }
4373
this.$logger.warn(err.message);
74+
this.$logger.trace("Required peerDependencies are: ", err.peersDepending);
4475
} else {
4576
// All other errors should be handled by the caller code.
4677
throw err;
4778
}
4879
}
49-
50-
let jsonContentAfter = this.$fs.readJson(path.join(pathToSave, "package.json")).wait();
51-
let dependenciesAfter = _.keys(jsonContentAfter.dependencies).concat(_.keys(jsonContentAfter.devDependencies));
52-
53-
/** This diff is done in case the installed pakcage is a URL address, a path to local directory or a .tgz file
54-
* in these cases we don't have the package name and we can't rely on "npm install --json"" option
55-
* to get the project name because we have to parse the output from the stdout and we have no controll over it (so other messages may be mangled in stdout)
56-
* The solution is to compare package.json project dependencies before and after install and get the name of the installed package,
57-
* even if it's installed through local path or URL. If command installes more than one package, only the package originally installed is returned.
58-
*/
59-
let dependencyDiff = _(jsonContentAfter.dependencies)
60-
.omitBy((val: string, key: string) => jsonContentBefore && jsonContentBefore.dependencies && jsonContentBefore.dependencies[key] && jsonContentBefore.dependencies[key] === val)
61-
.keys()
62-
.value();
63-
64-
let devDependencyDiff = _(jsonContentAfter.devDependencies)
65-
.omitBy((val: string, key: string) => jsonContentBefore && jsonContentBefore.devDependencies && jsonContentBefore.devDependencies[key] && jsonContentBefore.devDependencies[key] === val)
66-
.keys()
67-
.value();
68-
69-
let diff = dependencyDiff.concat(devDependencyDiff);
70-
71-
if(diff.length <= 0 && dependenciesBefore.length === dependenciesAfter.length && packageName !== pathToSave) {
72-
this.$errors.failWithoutHelp(`The plugin ${packageName} is already installed`);
73-
}
74-
if(diff.length <= 0 && dependenciesBefore.length !== dependenciesAfter.length) {
75-
this.$errors.failWithoutHelp(`Couldn't install package correctly`);
76-
}
77-
78-
return diff;
7980
}).future<any>()();
8081
}
8182

8283
public uninstall(packageName: string, config?: any, path?: string): IFuture<any> {
83-
let flags = this.getFlagsString(config, false);
84-
return this.$childProcess.exec(`npm uninstall ${packageName} ${flags}`, { cwd: path });
84+
return this.loadAndExecute("uninstall", [[packageName]], { config, path });
8585
}
8686

87-
public search(filter: string[], config: any): IFuture<any> {
88-
let args = (<any[]>([filter] || [])).concat(config.silent);
89-
return this.$childProcess.exec(`npm search ${args.join(" ")}`);
87+
public search(filter: string[], silent: boolean): IFuture<any> {
88+
let args = (<any[]>([filter] || [])).concat(silent);
89+
return this.loadAndExecute("search", args);
9090
}
9191

92-
public view(packageName: string, config: any): IFuture<any> {
93-
return (() => {
94-
let flags = this.getFlagsString(config, false);
95-
let viewResult = this.$childProcess.exec(`npm view ${packageName} ${flags}`).wait();
96-
return JSON.parse(viewResult);
97-
}).future<any>()();
92+
public cache(packageName: string, version: string, config?: any): IFuture<IDependencyData> {
93+
// function cache (pkg, ver, where, scrub, cb)
94+
return this.loadAndExecute("cache", [packageName, version, undefined, false], { subCommandName: "add", config: config });
9895
}
9996

100-
private getNpmExecutableName(): string {
101-
let npmExecutableName = "npm";
97+
public cacheUnpack(packageName: string, version: string, unpackTarget?: string): IFuture<void> {
98+
// function unpack (pkg, ver, unpackTarget, dMode, fMode, uid, gid, cb)
99+
return this.loadAndExecute("cache", [packageName, version, unpackTarget, null, null, null, null], { subCommandName: "unpack" });
100+
}
102101

103-
if (this.$hostInfo.isWindows) {
104-
npmExecutableName += ".cmd";
105-
}
102+
public view(packageName: string, propertyName: string): IFuture<any> {
103+
return this.loadAndExecute("view", [[packageName, propertyName], [false]]);
104+
}
106105

107-
return npmExecutableName;
106+
public executeNpmCommand(npmCommandName: string, currentWorkingDirectory: string): IFuture<any> {
107+
return this.$childProcess.exec(npmCommandName, { cwd: currentWorkingDirectory });
108108
}
109109

110-
private getFlagsString(config: any, asArray: boolean) : any{
111-
let array:Array<string> = [];
112-
for(let flag in config) {
113-
if(config[flag]) {
114-
if(flag==="dist-tags" || flag==="versions") {
115-
array.push(` ${flag}`);
116-
continue;
117-
}
118-
array.push(`--${flag}`);
110+
private loadAndExecute(commandName: string, args: any[], opts?: INpmOpts): IFuture<any> {
111+
return (() => {
112+
opts = opts || {};
113+
this.load(opts.config).wait();
114+
return this.executeCore(commandName, args, opts).wait();
115+
}).future<any>()();
116+
}
117+
118+
private executeCore(commandName: string, args: any[], opts?: INpmOpts): IFuture<any> {
119+
let future = new Future<any>();
120+
let oldNpmPath: string = undefined;
121+
let callback = (err: Error, data: any) => {
122+
if (oldNpmPath) {
123+
(<any>npm).prefix = oldNpmPath;
119124
}
125+
126+
if (err) {
127+
future.throw(err);
128+
} else {
129+
future.return(data);
130+
}
131+
};
132+
args.push(callback);
133+
134+
if (opts && opts.path) {
135+
oldNpmPath = npm.prefix;
136+
(<any>npm).prefix = opts.path;
120137
}
121-
if(asArray) {
122-
return array;
123-
}
124138

125-
return array.join(" ");
139+
let subCommandName: string = opts.subCommandName;
140+
let command = subCommandName ? npm.commands[commandName][subCommandName] : npm.commands[commandName];
141+
command.apply(this, args);
142+
143+
return future;
126144
}
127145
}
128146
$injector.register("npm", NodePackageManager);

0 commit comments

Comments
 (0)