Summary: We're skipping the signing and editing of EXEs on Windows. This is only temporary but I want to have an atomic commit we can go back to. This is to avoid cache eviction due to version numbers being encoded in the binary. This means you're not getting the logo on the binary and copyright information, etc. We're not actually shipping these right now, so the real-world impact of this is zero. Reviewed By: mweststrate Differential Revision: D25973944 fbshipit-source-id: d076919acfaac1f618178294baff3e9122d820bf
282 lines
7.7 KiB
TypeScript
Executable File
282 lines
7.7 KiB
TypeScript
Executable File
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @format
|
|
*/
|
|
|
|
import path from 'path';
|
|
import fs from 'fs-extra';
|
|
import {Platform, Arch, ElectronDownloadOptions, build} from 'electron-builder';
|
|
import {spawn} from 'promisify-child-process';
|
|
import {
|
|
buildFolder,
|
|
compileRenderer,
|
|
compileMain,
|
|
die,
|
|
getVersionNumber,
|
|
genMercurialRevision,
|
|
generatePluginEntryPoints,
|
|
} from './build-utils';
|
|
import fetch from '@adobe/node-fetch-retry';
|
|
import {getIcons, buildLocalIconPath, getIconURL} from '../app/src/utils/icons';
|
|
import isFB from './isFB';
|
|
import copyPackageWithDependencies from './copy-package-with-dependencies';
|
|
import {staticDir, distDir} from './paths';
|
|
import yargs from 'yargs';
|
|
|
|
const argv = yargs
|
|
.usage('yarn build [args]')
|
|
.version(false)
|
|
.options({
|
|
mac: {
|
|
type: 'boolean',
|
|
group: 'targets',
|
|
},
|
|
'mac-dmg': {
|
|
type: 'boolean',
|
|
group: 'targets',
|
|
},
|
|
win: {
|
|
type: 'boolean',
|
|
group: 'targets',
|
|
},
|
|
linux: {
|
|
type: 'boolean',
|
|
group: 'targets',
|
|
},
|
|
'linux-deb': {
|
|
type: 'boolean',
|
|
group: 'targets',
|
|
},
|
|
'linux-snap': {
|
|
type: 'boolean',
|
|
group: 'targets',
|
|
},
|
|
version: {
|
|
description:
|
|
'Unique build identifier to be used as the version patch part for the build',
|
|
type: 'number',
|
|
default: 0,
|
|
},
|
|
channel: {
|
|
description: 'Release channel for the build',
|
|
choices: ['stable', 'insiders'],
|
|
default: 'stable',
|
|
},
|
|
})
|
|
.help()
|
|
.strict()
|
|
.check((argv) => {
|
|
const targetSpecified =
|
|
argv.mac ||
|
|
argv['mac-dmg'] ||
|
|
argv.win ||
|
|
argv.linux ||
|
|
argv['linux-deb'] ||
|
|
argv['linux-snap'];
|
|
if (!targetSpecified) {
|
|
throw new Error('No targets specified. eg. --mac, --win, or --linux');
|
|
}
|
|
return true;
|
|
})
|
|
.parse(process.argv.slice(1));
|
|
|
|
if (isFB) {
|
|
process.env.FLIPPER_FB = 'true';
|
|
}
|
|
|
|
process.env.FLIPPER_RELEASE_CHANNEL = argv.channel;
|
|
|
|
async function generateManifest(versionNumber: string) {
|
|
await fs.writeFile(
|
|
path.join(distDir, 'manifest.json'),
|
|
JSON.stringify({
|
|
package: 'com.facebook.sonar',
|
|
version_name: versionNumber,
|
|
}),
|
|
);
|
|
}
|
|
|
|
async function modifyPackageManifest(
|
|
buildFolder: string,
|
|
versionNumber: string,
|
|
hgRevision: string | null,
|
|
channel: string,
|
|
) {
|
|
// eslint-disable-next-line no-console
|
|
console.log('Creating package.json manifest');
|
|
const manifest = require('../package.json');
|
|
const manifestStatic = require('../static/package.json');
|
|
|
|
// The manifest's dependencies are bundled with the final app by
|
|
// electron-builder. We want to bundle the dependencies from the static-folder
|
|
// because all dependencies from the root-folder are already bundled by metro.
|
|
manifest.dependencies = manifestStatic.dependencies;
|
|
manifest.main = 'index.js';
|
|
manifest.version = versionNumber;
|
|
if (hgRevision != null) {
|
|
manifest.revision = hgRevision;
|
|
}
|
|
manifest.releaseChannel = channel;
|
|
await fs.writeFile(
|
|
path.join(buildFolder, 'package.json'),
|
|
JSON.stringify(manifest, null, ' '),
|
|
);
|
|
}
|
|
|
|
async function buildDist(buildFolder: string) {
|
|
const targetsRaw: Map<Platform, Map<Arch, string[]>>[] = [];
|
|
const postBuildCallbacks: (() => void)[] = [];
|
|
|
|
if (argv.mac || argv['mac-dmg']) {
|
|
targetsRaw.push(Platform.MAC.createTarget(['dir']));
|
|
// You can build mac apps on Linux but can't build dmgs, so we separate those.
|
|
if (argv['mac-dmg']) {
|
|
targetsRaw.push(Platform.MAC.createTarget(['dmg']));
|
|
}
|
|
postBuildCallbacks.push(() =>
|
|
spawn('zip', ['-qyr9', '../Flipper-mac.zip', 'Flipper.app'], {
|
|
cwd: path.join(distDir, 'mac'),
|
|
encoding: 'utf-8',
|
|
}),
|
|
);
|
|
}
|
|
if (argv.linux || argv['linux-deb'] || argv['linux-snap']) {
|
|
targetsRaw.push(Platform.LINUX.createTarget(['zip']));
|
|
|
|
if (argv['linux-deb']) {
|
|
// linux targets can be:
|
|
// AppImage, snap, deb, rpm, freebsd, pacman, p5p, apk, 7z, zip, tar.xz, tar.lz, tar.gz, tar.bz2, dir
|
|
targetsRaw.push(Platform.LINUX.createTarget(['deb']));
|
|
}
|
|
if (argv['linux-snap']) {
|
|
targetsRaw.push(Platform.LINUX.createTarget(['snap']));
|
|
}
|
|
}
|
|
if (argv.win) {
|
|
targetsRaw.push(Platform.WINDOWS.createTarget(['zip']));
|
|
}
|
|
|
|
if (!targetsRaw.length) {
|
|
throw new Error('No targets specified. eg. --mac, --win, or --linux');
|
|
}
|
|
|
|
// merge all target maps into a single map
|
|
let targetsMerged: [Platform, Map<Arch, string[]>][] = [];
|
|
for (const target of targetsRaw) {
|
|
targetsMerged = targetsMerged.concat(Array.from(target));
|
|
}
|
|
const targets = new Map(targetsMerged);
|
|
|
|
const electronDownloadOptions: ElectronDownloadOptions = {};
|
|
if (process.env.electron_config_cache) {
|
|
electronDownloadOptions.cache = process.env.electron_config_cache;
|
|
}
|
|
|
|
try {
|
|
await build({
|
|
publish: 'never',
|
|
config: {
|
|
appId: `com.facebook.sonar`,
|
|
productName: 'Flipper',
|
|
directories: {
|
|
buildResources: buildFolder,
|
|
output: distDir,
|
|
},
|
|
electronDownload: electronDownloadOptions,
|
|
npmRebuild: false,
|
|
linux: {
|
|
executableName: 'flipper',
|
|
},
|
|
mac: {
|
|
bundleVersion: '50.0.0',
|
|
},
|
|
win: {
|
|
signAndEditExecutable: !isFB,
|
|
},
|
|
},
|
|
projectDir: buildFolder,
|
|
targets,
|
|
});
|
|
return await Promise.all(postBuildCallbacks.map((p) => p()));
|
|
} catch (err) {
|
|
return die(err);
|
|
}
|
|
}
|
|
|
|
async function copyStaticFolder(buildFolder: string) {
|
|
console.log(`⚙️ Copying static package with dependencies...`);
|
|
await copyPackageWithDependencies(staticDir, buildFolder);
|
|
console.log('✅ Copied static package with dependencies.');
|
|
}
|
|
|
|
function downloadIcons(buildFolder: string) {
|
|
const iconURLs = Object.entries(getIcons()).reduce<
|
|
{
|
|
name: string;
|
|
size: number;
|
|
density: number;
|
|
}[]
|
|
>((acc, [name, sizes]) => {
|
|
acc.push(
|
|
// get icons in @1x and @2x
|
|
...sizes.map((size) => ({name, size, density: 1})),
|
|
...sizes.map((size) => ({name, size, density: 2})),
|
|
);
|
|
return acc;
|
|
}, []);
|
|
|
|
return Promise.all(
|
|
iconURLs.map(({name, size, density}) => {
|
|
const url = getIconURL(name, size, density);
|
|
return fetch(url, {})
|
|
.then((res) => {
|
|
if (res.status !== 200) {
|
|
throw new Error(
|
|
// eslint-disable-next-line prettier/prettier
|
|
`Could not download the icon ${name} from ${url}: got status ${
|
|
res.status
|
|
}`,
|
|
);
|
|
}
|
|
return res;
|
|
})
|
|
.then(
|
|
(res) =>
|
|
new Promise((resolve, reject) => {
|
|
const fileStream = fs.createWriteStream(
|
|
path.join(buildFolder, buildLocalIconPath(name, size, density)),
|
|
);
|
|
res.body.pipe(fileStream);
|
|
res.body.on('error', reject);
|
|
fileStream.on('finish', resolve);
|
|
}),
|
|
);
|
|
}),
|
|
);
|
|
}
|
|
|
|
(async () => {
|
|
const dir = await buildFolder();
|
|
// eslint-disable-next-line no-console
|
|
console.log('Created build directory', dir);
|
|
|
|
await compileMain();
|
|
await generatePluginEntryPoints(argv.channel === 'insiders');
|
|
await copyStaticFolder(dir);
|
|
await downloadIcons(dir);
|
|
await compileRenderer(dir);
|
|
const versionNumber = getVersionNumber(argv.version);
|
|
const hgRevision = await genMercurialRevision();
|
|
await modifyPackageManifest(dir, versionNumber, hgRevision, argv.channel);
|
|
await fs.ensureDir(distDir);
|
|
await generateManifest(versionNumber);
|
|
await buildDist(dir);
|
|
// eslint-disable-next-line no-console
|
|
console.log('✨ Done');
|
|
process.exit();
|
|
})();
|