From fd838a428032fc2c9417f3ecde2582a9c51facf4 Mon Sep 17 00:00:00 2001 From: Evan Morikawa Date: Tue, 21 Feb 2017 14:36:18 -0500 Subject: [PATCH] [client-app] resolve symlinks before copying files Summary: In client-app/node_modules Lerna symlinks isomorphic-core to '../../'. When we copy everything over to our tmp directory when building, we copy over the relative symlink! Damn you lerna. We get around this by resolving the symlinks BEFORE copying and caching them in the installer task. Then the file copy always works. Also, for some reason the glob {absolute} param doesn't seem to work in the latest version. I'm manually creating an absolute path for the compile target since it's a bit more transparent what's happening anyway. Test Plan: `npm run build-client` Reviewers: spang, jerm, juan, halla Reviewed By: juan, halla Differential Revision: https://phab.nylas.com/D3988 --- .gitignore | 3 ++ .../client-app/build/tasks/package-task.js | 50 +++++++++++++------ 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index a0ed1bb8b..33e6f9753 100644 --- a/.gitignore +++ b/.gitignore @@ -43,5 +43,8 @@ node_modules # Built cloud files n1_cloud_dist +# Built Nylas Mail client +packages/client-app/dist + # Tests spec-saved-state.json diff --git a/packages/client-app/build/tasks/package-task.js b/packages/client-app/build/tasks/package-task.js index 13891a336..7a6ad9a0a 100644 --- a/packages/client-app/build/tasks/package-task.js +++ b/packages/client-app/build/tasks/package-task.js @@ -8,6 +8,7 @@ const fs = require('fs-plus'); const coffeereact = require('coffee-react'); const glob = require('glob'); const babel = require('babel-core'); +const symlinkedPackages = [] module.exports = (grunt) => { const packageJSON = grunt.config('appJSON'); @@ -46,25 +47,42 @@ module.exports = (grunt) => { callback(); } - function runCopySymlinkedPackages(buildPath, electronVersion, platform, arch, callback) { - console.log("---> Moving symlinked node modules / internal packages into build folder.") - + /** + * We have to resolve the symlink paths (and cache the results) before + * copying over the files since some symlinks may be relative paths (like + * those created by lerna). We'll keep absolute references of those paths + * for the symlink copy function to use after the packaging is complete. + */ + function resolveRealSymlinkPaths(appDir) { + console.log("---> Resolving symlinks"); const dirs = [ - path.join(buildPath, 'internal_packages'), - path.join(buildPath, 'node_modules'), + 'internal_packages', + 'node_modules', ]; dirs.forEach((dir) => { - fs.readdirSync(dir).forEach((packageName) => { - const packagePath = path.join(dir, packageName) - const realPackagePath = fs.realpathSync(packagePath).replace('/private/', '/') - if (realPackagePath !== packagePath) { - console.log(` ---> Copying ${realPackagePath} to ${packagePath}`); - fs.removeSync(packagePath); - fs.copySync(realPackagePath, packagePath); + absoluteDir = path.join(appDir, dir); + fs.readdirSync(absoluteDir).forEach((packageName) => { + const relativePackageDir = path.join(dir, packageName) + const absolutePackageDir = path.join(absoluteDir, packageName) + const realPackagePath = fs.realpathSync(absolutePackageDir).replace('/private/', '/') + if (realPackagePath !== absolutePackageDir) { + console.log(` ---> Resolving '${relativePackageDir}' to '${realPackagePath}'`) + symlinkedPackages.push({realPackagePath, relativePackageDir}) } }); }); + } + + function runCopySymlinkedPackages(buildPath, electronVersion, platform, arch, callback) { + console.log("---> Moving symlinked node modules / internal packages into build folder.") + + symlinkedPackages.forEach(({realPackagePath, relativePackageDir}) => { + const packagePath = path.join(buildPath, relativePackageDir) + console.log(` ---> Copying ${realPackagePath} to ${packagePath}`); + fs.removeSync(packagePath); + fs.copySync(realPackagePath, packagePath); + }); callback(); } @@ -84,7 +102,8 @@ module.exports = (grunt) => { console.log("---> Running babel and coffeescript transpilers") grunt.config('source:coffeescript').forEach(pattern => { - glob.sync(pattern, {cwd: buildPath, absolute: true}).forEach((coffeepath) => { + glob.sync(pattern, {cwd: buildPath}).forEach((relPath) => { + const coffeepath = path.join(buildPath, relPath) if (/(node_modules|\.js$)/.test(coffeepath)) return console.log(` ---> Compiling ${coffeepath.slice(coffeepath.indexOf("/app") + 4)}`) const outPath = coffeepath.replace(path.extname(coffeepath), '.js'); @@ -105,7 +124,8 @@ module.exports = (grunt) => { }); grunt.config('source:es6').forEach(pattern => { - glob.sync(pattern, {cwd: buildPath, absolute: true}).forEach((es6Path) => { + glob.sync(pattern, {cwd: buildPath}).forEach((relPath) => { + const es6Path = path.join(buildPath, relPath) if (/(node_modules|\.js$)/.test(es6Path)) return const outPath = es6Path.replace(path.extname(es6Path), '.js'); console.log(` ---> Compiling ${es6Path.slice(es6Path.indexOf("/app") + 4)}`) @@ -270,6 +290,8 @@ module.exports = (grunt) => { time += 1; }, 1000) + resolveRealSymlinkPaths(grunt.config('appDir')) + packager(grunt.config.get('packager'), (err, appPaths) => { clearInterval(ongoing) if (err) {