Skip to content

Commit 32d168a

Browse files
Fatme Havaluovarosen-vladimirov
Fatme Havaluova
authored andcommitted
Fix symlinks that are added to output package and points to not existing location
1 parent 83c3d5c commit 32d168a

File tree

5 files changed

+134
-76
lines changed

5 files changed

+134
-76
lines changed

lib/services/platform-service.ts

+15-6
Original file line numberDiff line numberDiff line change
@@ -149,17 +149,26 @@ export class PlatformService implements IPlatformService {
149149
platform = platform.toLowerCase();
150150

151151
var platformData = this.$platformsData.getPlatformData(platform);
152+
let appDestinationDirectoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
153+
let lastModifiedTime = this.$fs.exists(appDestinationDirectoryPath).wait() ?
154+
this.$fs.getFsStats(appDestinationDirectoryPath).wait().mtime : null;
152155

153156
// Copy app folder to native project
157+
this.$fs.ensureDirectoryExists(appDestinationDirectoryPath).wait();
154158
var appSourceDirectoryPath = path.join(this.$projectData.projectDir, constants.APP_FOLDER_NAME);
155-
159+
156160
// Delete the destination app in order to prevent EEXIST errors when symlinks are used.
157-
this.$fs.deleteDirectory(path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME)).wait();
158-
shell.cp("-R", appSourceDirectoryPath, platformData.appDestinationDirectoryPath);
161+
let contents = this.$fs.readDirectory(appDestinationDirectoryPath).wait();
162+
163+
_(contents)
164+
.filter(directoryName => directoryName !== "tns_modules")
165+
.each(directoryName => this.$fs.deleteDirectory(path.join(appDestinationDirectoryPath, directoryName)).wait())
166+
.value();
167+
shell.cp("-Rf", appSourceDirectoryPath, platformData.appDestinationDirectoryPath);
159168

160169
// Copy App_Resources to project root folder
161-
var appResourcesDirectoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME, constants.APP_RESOURCES_FOLDER_NAME);
162-
this.$fs.ensureDirectoryExists(platformData.appResourcesDestinationDirectoryPath).wait();
170+
this.$fs.ensureDirectoryExists(platformData.appResourcesDestinationDirectoryPath).wait(); // Should be deleted
171+
var appResourcesDirectoryPath = path.join(appDestinationDirectoryPath, constants.APP_RESOURCES_FOLDER_NAME);
163172
if (this.$fs.exists(appResourcesDirectoryPath).wait()) {
164173
platformData.platformProjectService.prepareAppResources(appResourcesDirectoryPath).wait();
165174
shell.cp("-R", path.join(appResourcesDirectoryPath, platformData.normalizedPlatformName, "*"), platformData.appResourcesDestinationDirectoryPath);
@@ -176,7 +185,7 @@ export class PlatformService implements IPlatformService {
176185
// Process node_modules folder
177186
this.$pluginsService.ensureAllDependenciesAreInstalled().wait();
178187
var tnsModulesDestinationPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME, PlatformService.TNS_MODULES_FOLDER_NAME);
179-
this.$broccoliBuilder.prepareNodeModules(tnsModulesDestinationPath, this.$projectData.projectDir).wait();
188+
this.$broccoliBuilder.prepareNodeModules(tnsModulesDestinationPath, this.$projectData.projectDir, lastModifiedTime).wait();
180189

181190
this.$logger.out("Project successfully prepared");
182191
}).future<void>()();

lib/tools/broccoli/broccoli.d.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ interface BroccoliNode {
152152
}
153153

154154
interface IBroccoliBuilder {
155-
prepareNodeModules(outputPath: string, projectDir: string): IFuture<void>;
155+
prepareNodeModules(outputPath: string, projectDir: string, lastModifiedTime?: Date): IFuture<void>;
156156
}
157157

158158
interface IDiffResult {
@@ -162,6 +162,7 @@ interface IDiffResult {
162162

163163
interface IBroccoliPlugin {
164164
rebuild(diff: IDiffResult): any;
165+
rebuildChangedDirectories?(changedDirectories: string[]): void;
165166
cleanup? () : void;
166167
}
167168

lib/tools/broccoli/builder.ts

+66-14
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,81 @@ let broccoli = require('broccoli');
55
let path = require('path');
66
import Future = require("fibers/future");
77
import {TreeDiffer} from './tree-differ';
8-
import destCopy = require('./node-modules-dest-copy');
8+
import destCopyLib = require('./node-modules-dest-copy');
9+
10+
var gulp = require("gulp");
11+
var vinylFilterSince = require('vinyl-filter-since')
12+
var through = require("through2");
913

1014
export class Builder implements IBroccoliBuilder {
15+
private nodeModules: any = {};
16+
1117
constructor(private $fs: IFileSystem,
1218
private $nodeModulesTree: INodeModulesTree,
1319
private $projectDataService: IProjectDataService,
20+
private $injector: IInjector,
1421
private $logger: ILogger) { }
1522

16-
public prepareNodeModules(absoluteOutputPath: string, projectDir: string): IFuture<void> {
23+
public prepareNodeModules(absoluteOutputPath: string, projectDir: string, lastModifiedTime?: Date): IFuture<void> {
1724
return (() => {
18-
// TODO: figure out a better way for doing this
19-
this.$projectDataService.initialize(projectDir);
20-
let cachedNodeModulesPath = this.$projectDataService.getValue("node-modules-cache-path").wait();
21-
if (cachedNodeModulesPath && this.$fs.exists(cachedNodeModulesPath).wait()) {
22-
let diffTree = new TreeDiffer(cachedNodeModulesPath);
23-
let diffTreeResult = diffTree.diffTree(path.join(projectDir, absoluteOutputPath, "node_modules"));
24-
25-
if(diffTreeResult.changedDirectories.length > 0 || diffTreeResult.removedDirectories.length > 0) {
26-
this.rebuildNodeModulesTree(absoluteOutputPath, projectDir).wait();
27-
}
28-
} else {
29-
this.rebuildNodeModulesTree(absoluteOutputPath, projectDir).wait();
25+
let isNodeModulesModified = false;
26+
let nodeModulesPath = path.join(projectDir, "node_modules");
27+
28+
if(lastModifiedTime) {
29+
let pipeline = gulp.src(path.join(projectDir, "node_modules/**"))
30+
.pipe(vinylFilterSince(lastModifiedTime))
31+
.pipe(through.obj( (chunk: any, enc: any, cb: Function) => {
32+
if(chunk.path === nodeModulesPath) {
33+
isNodeModulesModified = true;
34+
}
35+
36+
if(!isNodeModulesModified) {
37+
let rootModuleName = chunk.path.split(nodeModulesPath)[1].split(path.sep)[1];
38+
let rootModuleFullPath = path.join(nodeModulesPath, rootModuleName);
39+
this.nodeModules[rootModuleFullPath] = rootModuleFullPath;
40+
}
41+
42+
cb(null);
43+
}))
44+
.pipe(gulp.dest(absoluteOutputPath));
45+
46+
let future = new Future<void>();
47+
48+
pipeline.on('end', (err: any, data: any) => {
49+
if(err) {
50+
future.throw(err);
51+
} else {
52+
future.return();
53+
}
54+
});
55+
56+
future.wait();
57+
}
58+
59+
if(isNodeModulesModified && this.$fs.exists(absoluteOutputPath).wait()) {
60+
let currentPreparedTnsModules = this.$fs.readDirectory(absoluteOutputPath).wait();
61+
let tnsModulesInApp = this.$fs.readDirectory(path.join(projectDir, "app", "tns_modules")).wait();
62+
let modulesToDelete = _.difference(currentPreparedTnsModules, tnsModulesInApp);
63+
_.each(modulesToDelete, moduleName => this.$fs.deleteDirectory(path.join(absoluteOutputPath, moduleName)).wait())
64+
}
65+
66+
if(!lastModifiedTime || isNodeModulesModified) {
67+
let nodeModulesDirectories = this.$fs.readDirectory(nodeModulesPath).wait();
68+
_.each(nodeModulesDirectories, nodeModuleDirectoryName => {
69+
let nodeModuleFullPath = path.join(nodeModulesPath, nodeModuleDirectoryName);
70+
this.nodeModules[nodeModuleFullPath] = nodeModuleFullPath;
71+
});
3072
}
73+
74+
let destCopy = this.$injector.resolve(destCopyLib.DestCopy, {
75+
inputPath: projectDir,
76+
cachePath: "",
77+
outputRoot: absoluteOutputPath,
78+
projectDir: projectDir
79+
});
80+
81+
destCopy.rebuildChangedDirectories(_.keys(this.nodeModules));
82+
3183
}).future<void>()();
3284
}
3385

lib/tools/broccoli/node-modules-dest-copy.ts

+48-55
Original file line numberDiff line numberDiff line change
@@ -14,57 +14,66 @@ import constants = require("./../../constants");
1414
* and tees a copy to the given path outside the tmp dir.
1515
*/
1616
export class DestCopy implements IBroccoliPlugin {
17-
constructor(private inputPath: string, private cachePath: string, private outputRoot: string, private projectDir: string) {}
18-
19-
public rebuild(treeDiff: IDiffResult): void {
20-
let dependencies = this.getDependencies();
21-
let devDependencies = this.getDevDependencies(this.projectDir);
22-
23-
treeDiff.changedDirectories.forEach(changedDirectory => {
24-
let changedDirectoryAbsolutePath = path.join(this.inputPath, constants.NODE_MODULES_FOLDER_NAME, changedDirectory);
25-
let packageJsonFiles = [path.join(changedDirectoryAbsolutePath, "package.json")];
26-
let nodeModulesFolderPath = path.join(changedDirectoryAbsolutePath, "node_modules");
27-
packageJsonFiles = packageJsonFiles.concat(this.enumeratePackageJsonFilesSync(nodeModulesFolderPath));
28-
29-
_.each(packageJsonFiles, packageJsonFilePath => {
30-
let fileContent = require(packageJsonFilePath);
31-
let isPlugin = fileContent.nativescript;
17+
private dependencies: IDictionary<any> = null;
18+
private devDependencies: IDictionary<any> = null;
3219

33-
if(!devDependencies[fileContent.name]) { // Don't flatten dev dependencies
34-
35-
let currentDependency = {
36-
name: fileContent.name,
37-
version: fileContent.version,
38-
directory: path.dirname(packageJsonFilePath),
39-
isPlugin: isPlugin
40-
};
20+
constructor(private inputPath: string, private cachePath: string, private outputRoot: string, private projectDir: string) {
21+
this.dependencies = Object.create(null);
22+
this.devDependencies = this.getDevDependencies(projectDir);
23+
}
24+
25+
public rebuildChangedDirectories(changedDirectories: string[]): void {
26+
_.each(changedDirectories, changedDirectoryAbsolutePath => {
27+
let pathToPackageJson = path.join(changedDirectoryAbsolutePath, "package.json");
28+
if(fs.existsSync(pathToPackageJson)) {
29+
let packageJsonFiles = [pathToPackageJson];
30+
let nodeModulesFolderPath = path.join(changedDirectoryAbsolutePath, "node_modules");
31+
packageJsonFiles = packageJsonFiles.concat(this.enumeratePackageJsonFilesSync(nodeModulesFolderPath));
4132

42-
let addedDependency = dependencies[currentDependency.name];
43-
if (addedDependency) {
44-
if (semver.gt(currentDependency.version, addedDependency.version)) {
45-
let currentDependencyMajorVersion = semver.major(currentDependency.version);
46-
let addedDependencyMajorVersion = semver.major(addedDependency.version);
33+
_.each(packageJsonFiles, packageJsonFilePath => {
34+
let fileContent = require(packageJsonFilePath);
35+
let isPlugin = fileContent.nativescript;
4736

48-
let message = `The depedency located at ${addedDependency.directory} with version ${addedDependency.version} will be replaced with dependency located at ${currentDependency.directory} with version ${currentDependency.version}`;
49-
let logger = $injector.resolve("$logger");
50-
currentDependencyMajorVersion === addedDependencyMajorVersion ? logger.out(message) : logger.warn(message);
51-
52-
dependencies[currentDependency.name] = currentDependency;
37+
if(!this.devDependencies[fileContent.name]) { // Don't flatten dev dependencies
38+
39+
let currentDependency = {
40+
name: fileContent.name,
41+
version: fileContent.version,
42+
directory: path.dirname(packageJsonFilePath),
43+
isPlugin: isPlugin
44+
};
45+
46+
let addedDependency = this.dependencies[currentDependency.name];
47+
if (addedDependency) {
48+
if (semver.gt(currentDependency.version, addedDependency.version)) {
49+
let currentDependencyMajorVersion = semver.major(currentDependency.version);
50+
let addedDependencyMajorVersion = semver.major(addedDependency.version);
51+
52+
let message = `The depedency located at ${addedDependency.directory} with version ${addedDependency.version} will be replaced with dependency located at ${currentDependency.directory} with version ${currentDependency.version}`;
53+
let logger = $injector.resolve("$logger");
54+
currentDependencyMajorVersion === addedDependencyMajorVersion ? logger.out(message) : logger.warn(message);
55+
56+
this.dependencies[currentDependency.name] = currentDependency;
57+
}
58+
} else {
59+
this.dependencies[currentDependency.name] = currentDependency;
5360
}
54-
} else {
55-
dependencies[currentDependency.name] = currentDependency;
5661
}
57-
}
58-
});
62+
});
63+
}
5964
});
6065

61-
_.each(dependencies, dependency => {
62-
shelljs.cp("-R", dependency.directory, this.outputRoot);
66+
_.each(this.dependencies, dependency => {
67+
shelljs.cp("-Rf", dependency.directory, this.outputRoot);
6368
shelljs.rm("-rf", path.join(this.outputRoot, dependency.name, "node_modules"));
6469
if(dependency.isPlugin) {
6570
shelljs.rm("-rf", path.join(this.outputRoot, dependency.name, "platforms"));
6671
}
6772
});
73+
}
74+
75+
public rebuild(treeDiff: IDiffResult): void {
76+
this.rebuildChangedDirectories(treeDiff.changedDirectories);
6877

6978
// Cache input tree
7079
let projectFilePath = path.join(this.projectDir, constants.PACKAGE_JSON_FILE_NAME);
@@ -73,22 +82,6 @@ export class DestCopy implements IBroccoliPlugin {
7382
fs.writeFileSync(projectFilePath, JSON.stringify(projectFileContent, null, "\t"), { encoding: "utf8" });
7483
}
7584

76-
private getDependencies(): IDictionary<any> {
77-
let result = Object.create(null);
78-
if(fs.existsSync(this.outputRoot)) {
79-
let dirs = fs.readdirSync(this.outputRoot);
80-
_.each(dirs, dir => {
81-
let filePath = path.join(dir, constants.PACKAGE_JSON_FILE_NAME);
82-
if(fs.existsSync(filePath)) {
83-
let fileContent = require(filePath);
84-
result[fileContent.name] = fileContent;
85-
}
86-
});
87-
}
88-
89-
return result;
90-
}
91-
9285
private getDevDependencies(projectDir: string): IDictionary<any> {
9386
let projectFilePath = path.join(projectDir, constants.PACKAGE_JSON_FILE_NAME);
9487
let projectFileContent = require(projectFilePath);

package.json

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"fibers": "https://github.com/icenium/node-fibers/tarball/v1.0.5.1",
3838
"filesize": "2.0.3",
3939
"gaze": "0.5.1",
40+
"gulp": "3.9.0",
4041
"iconv-lite": "0.4.4",
4142
"inquirer": "0.8.2",
4243
"ios-sim-portable": "1.0.8",
@@ -65,7 +66,9 @@
6566
"shelljs": "0.3.0",
6667
"tabtab": "https://github.com/Icenium/node-tabtab/tarball/master",
6768
"temp": "0.8.1",
69+
"through2": "2.0.0",
6870
"utf-8-validate": "https://github.com/telerik/utf-8-validate/tarball/master",
71+
"vinyl-filter-since": "2.0.0",
6972
"winreg": "0.0.12",
7073
"ws": "0.7.1",
7174
"xcode": "https://github.com/NativeScript/node-xcode/archive/NativeScript-1.1.tar.gz",

0 commit comments

Comments
 (0)