mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-11-12 04:25:31 +08:00
284 lines
10 KiB
JavaScript
284 lines
10 KiB
JavaScript
/* eslint global-require: 0 *//* eslint prefer-template: 0 */
|
|
/* eslint quote-props: 0 */
|
|
const packager = require('electron-packager');
|
|
const path = require('path');
|
|
const util = require('util');
|
|
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 symlinkedPackages = []
|
|
|
|
module.exports = (grunt) => {
|
|
const packageJSON = grunt.config('appJSON');
|
|
const babelPath = path.join(grunt.config('rootDir'), '.babelrc')
|
|
const babelOptions = JSON.parse(fs.readFileSync(babelPath))
|
|
|
|
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();
|
|
}
|
|
|
|
/**
|
|
* 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 = [
|
|
'internal_packages',
|
|
'src',
|
|
'spec',
|
|
'node_modules',
|
|
];
|
|
|
|
dirs.forEach((dir) => {
|
|
const 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();
|
|
}
|
|
|
|
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}).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');
|
|
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}).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)}`)
|
|
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 Mail',
|
|
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": [ // These are all relative to client-app
|
|
/.*\.watchmanconfig.*/,
|
|
|
|
// top level dirs we never want
|
|
/^\/build.*/,
|
|
/^\/dist.*/,
|
|
/^\/docs.*/,
|
|
/^\/docs_src.*/,
|
|
/^\/script.*/,
|
|
/^\/spec.*/,
|
|
|
|
// general dirs we never want
|
|
/[/]+gh-pages$/,
|
|
/[/]+docs$/,
|
|
/[/]+obj[/]+gen/,
|
|
/[/]+\.deps$/,
|
|
|
|
// File types we know we never want in the prod build
|
|
/\.md$/i,
|
|
/\.log$/i,
|
|
/\.yml$/i,
|
|
/\.gz/i,
|
|
/\.zip/i,
|
|
/\.pdb$/,
|
|
/\.h$/,
|
|
/\.cc$/,
|
|
/\.ts$/,
|
|
/\.flow$/,
|
|
/\.gyp/,
|
|
/\.mk/,
|
|
/\.dYSM$/,
|
|
|
|
// 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,
|
|
/**
|
|
* This will automatically look for the identity in the keychain. It
|
|
* runs the `security find-identity` command. Note that
|
|
* setup-mac-keychain-task needs to be run first
|
|
*/
|
|
'osx-sign': !!process.env.SIGN_BUILD,
|
|
'win32metadata': {
|
|
CompanyName: 'Nylas, Inc.',
|
|
FileDescription: 'Nylas Mail',
|
|
LegalCopyright: `Copyright (C) 2014-${new Date().getFullYear()} Nylas, Inc. All rights reserved.`,
|
|
ProductName: 'Nylas Mail',
|
|
},
|
|
// 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",
|
|
'afterCopy': [
|
|
runCopyPlatformSpecificResources,
|
|
runCopyAPM,
|
|
runCopySymlinkedPackages,
|
|
runTranspilers,
|
|
],
|
|
},
|
|
})
|
|
|
|
grunt.registerTask('package', 'Package Nylas Mail', function pack() {
|
|
const done = this.async();
|
|
const start = Date.now();
|
|
|
|
console.log('---> Running packager with options:');
|
|
console.log(util.inspect(grunt.config.get('packager'), true, 7, true));
|
|
|
|
const ongoing = setInterval(() => {
|
|
const elapsed = Math.round((Date.now() - start) / 1000.0)
|
|
console.log(`---> Packaging for ${elapsed}s`);
|
|
}, 1000)
|
|
|
|
resolveRealSymlinkPaths(grunt.config('appDir'))
|
|
|
|
packager(grunt.config.get('packager'), (err, appPaths) => {
|
|
clearInterval(ongoing)
|
|
if (err) {
|
|
grunt.fail.fatal(err);
|
|
return done(err);
|
|
}
|
|
console.log(`---> Done Successfully. Built into: ${appPaths}`);
|
|
return done();
|
|
});
|
|
});
|
|
};
|