Mailspring/build/tasks/package-task.js

256 lines
8.9 KiB
JavaScript

/* eslint prefer-template: 0 */
/* eslint quote-props: 0 */
const packager = require('electron-packager');
const path = require('path');
const tmpdir = path.resolve(require('os').tmpdir(), 'nylas-build');
const fs = require('fs-plus');
const coffeereact = require('coffee-react');
const glob = require('glob');
const babel = require('babel-core');
const packageJSON = require('../../package.json')
const babelOptions = require("../../static/babelrc");
module.exports = (grunt) => {
function runCopyAPM(buildPath, electronVersion, platform, arch, callback) {
// Move APM up out of the /app folder which will be inside the ASAR
const apmTargetDir = path.resolve(buildPath, '..', 'apm');
fs.moveSync(path.join(buildPath, 'apm'), apmTargetDir)
// Move /apm/node_modules/atom-package-manager up a level. We're essentially
// pulling the atom-package-manager module up outside of the node_modules folder,
// which is necessary because npmV3 installs nested dependencies in the same dir.
const apmPackageDir = path.join(apmTargetDir, 'node_modules', 'atom-package-manager')
for (const name of fs.readdirSync(apmPackageDir)) {
fs.renameSync(path.join(apmPackageDir, name), path.join(apmTargetDir, name));
}
const apmSymlink = path.join(apmTargetDir, 'node_modules', '.bin', 'apm');
if (fs.existsSync(apmSymlink)) {
fs.unlinkSync(apmSymlink);
}
fs.rmdirSync(apmPackageDir);
callback();
}
function runCopyPlatformSpecificResources(buildPath, electronVersion, platform, arch, callback) {
// these files (like nylas-mailto-default.reg) go alongside the ASAR, not inside it,
// so we need to move out of the `app` directory.
const resourcesDir = path.resolve(buildPath, '..');
if (platform === 'win32') {
fs.copySync(path.resolve(grunt.config('appDir'), 'build', 'resources', 'win'), resourcesDir);
}
callback();
}
function runCopySymlinkedPackages(buildPath, electronVersion, platform, arch, callback) {
console.log(" -- Moving symlinked node modules / internal packages into build folder.")
const dirs = [
path.join(buildPath, 'internal_packages'),
path.join(buildPath, '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);
}
});
});
callback();
}
function runTranspilers(buildPath, electronVersion, platform, arch, callback) {
console.log(" -- Running babel and coffeescript transpilers")
grunt.config('source:coffeescript').forEach(pattern => {
glob.sync(pattern, {cwd: buildPath, absolute: true}).forEach((coffeepath) => {
const outPath = coffeepath.replace(path.extname(coffeepath), '.js');
const res = coffeereact.compile(grunt.file.read(coffeepath), {
bare: false,
join: false,
separator: grunt.util.normalizelf(grunt.util.linefeed),
sourceMap: true,
sourceRoot: '/',
generatedFile: path.basename(outPath),
sourceFiles: [path.relative(buildPath, coffeepath)],
});
grunt.file.write(outPath, `${res.js}\n//# sourceMappingURL=${path.basename(outPath)}.map\n`);
grunt.file.write(`${outPath}.map`, res.v3SourceMap);
fs.unlinkSync(coffeepath);
});
});
grunt.config('source:es6').forEach(pattern => {
glob.sync(pattern, {cwd: buildPath, absolute: true}).forEach((es6Path) => {
const outPath = es6Path.replace(path.extname(es6Path), '.js');
const res = babel.transformFileSync(es6Path, Object.assign(babelOptions, {
sourceMaps: true,
sourceRoot: '/',
sourceMapTarget: path.relative(buildPath, outPath),
sourceFileName: path.relative(buildPath, es6Path),
}));
grunt.file.write(outPath, `${res.code}\n//# sourceMappingURL=${path.basename(outPath)}.map\n`);
grunt.file.write(`${outPath}.map`, JSON.stringify(res.map));
fs.unlinkSync(es6Path);
});
});
callback();
}
const platform = grunt.option('platform');
// See: https://github.com/electron-userland/electron-packager/blob/master/usage.txt
grunt.config.merge({
'packager': {
'app-version': packageJSON.version,
'platform': platform,
'protocols': [{
name: "Nylas Protocol",
schemes: ["nylas"],
}, {
name: "Mailto Protocol",
schemes: ["mailto"],
}],
'dir': grunt.config('appDir'),
'app-category-type': "public.app-category.business",
'tmpdir': tmpdir,
'arch': {
'win32': 'ia32',
}[platform],
'icon': {
darwin: path.resolve(grunt.config('appDir'), 'build', 'resources', 'mac', 'nylas.icns'),
win32: path.resolve(grunt.config('appDir'), 'build', 'resources', 'win', 'nylas.ico'),
linux: undefined,
}[platform],
'name': {
darwin: 'Nylas N1',
win32: 'nylas',
linux: 'nylas',
}[platform],
'app-copyright': `Copyright (C) 2014-${new Date().getFullYear()} Nylas, Inc. All rights reserved.`,
'derefSymlinks': false,
'asar': {
'unpack': "{" + [
'*.node',
'**/vendor/**',
'examples/**',
'**/src/tasks/**',
'**/node_modules/spellchecker/**',
'**/node_modules/windows-shortcuts/**',
].join(',') + "}",
},
'ignore': [
// top level dirs we never want
'^[\\/]+arclib',
'^[\\/]+build',
'^[\\/]+electron',
'^[\\/]+flow-typed',
'^[\\/]+src[\\/]+pro',
'^[\\/]+spec_integration',
// general dirs we never want
'[\\/]+gh-pages$',
'[\\/]+docs$',
'[\\/]+obj[\\/]+gen',
'[\\/]+\\.deps$',
// specific files we never want
'\\.DS_Store$',
'\\.jshintrc$',
'\\.npmignore$',
'\\.pairs$',
'\\.travis\\.yml$',
'appveyor\\.yml$',
'\\.idea$',
'\\.editorconfig$',
'\\.lint$',
'\\.lintignore$',
'\\.arcconfig$',
'\\.flowconfig$',
'\\.jshintignore$',
'\\.gitattributes$',
'\\.gitkeep$',
'\\.pdb$',
'\\.cc$',
'\\.h$',
'\\.d\\.ts$',
'\\.js\\.flow$',
'\\.map$',
'binding\\.gyp$',
'target\\.mk$',
'\\.node\\.dYSM$',
'autoconf-\\d*\\.tar\\.gz$',
// specific (large) module bits we know we don't need
'node_modules[\\/]+less[\\/]+dist$',
'node_modules[\\/]+react[\\/]+dist$',
'node_modules[\\/].*[\\/]tests?$',
'node_modules[\\/].*[\\/]coverage$',
'node_modules[\\/].*[\\/]benchmark$',
'@paulbetts[\\/]+cld[\\/]+deps[\\/]+cld',
],
'out': grunt.config('outputDir'),
'overwrite': true,
'prune': true,
'osx-sign': {
identity: 'Developer ID Application: InboxApp, Inc. (L6VLD5R29R)',
},
'win32metadata': {
CompanyName: 'Nylas, Inc.',
FileDescription: 'The best email app for people and teams at work',
LegalCopyright: `Copyright (C) 2014-${new Date().getFullYear()} Nylas, Inc. All rights reserved.`,
ProductName: 'Nylas N1',
},
// NOTE: The following plist keys can NOT be set in the
// nylas-Info.plist since they are manually overridden by
// electron-packager based on this config file:
//
// CFBundleDisplayName: 'name',
// CFBundleExecutable: 'name',
// CFBundleIdentifier: 'app-bundle-id',
// CFBundleName: 'name'
//
// See https://github.com/electron-userland/electron-packager/blob/master/mac.js#L50
//
// Our own nylas-Info.plist gets extended on top of the
// Electron.app/Contents/Info.plist. A majority of the defaults are
// left in the Electron Info.plist file
'extend-info': path.resolve(grunt.config('appDir'), 'build', 'resources', 'mac', 'nylas-Info.plist'),
'app-bundle-id': "com.nylas.nylas-mail",
'extra-resource': [
path.resolve(grunt.config('appDir'), 'build', 'resources', 'mac', 'Nylas Calendar.app'),
],
'afterCopy': [
runCopyPlatformSpecificResources,
runCopyAPM,
runCopySymlinkedPackages,
runTranspilers,
],
},
})
grunt.registerTask('packager', 'Package build of N1', function pack() {
const done = this.async()
console.log('----- Running build with options:');
console.log(JSON.stringify(grunt.config.get('packager'), null, 2));
packager(grunt.config.get('packager'), (err, appPaths) => {
if (err) {
console.error(err);
return;
}
console.log(`Done: ${appPaths}`);
done();
});
});
};