-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(android): implement remote snapshot generation
- Loading branch information
Gary Mathews
committed
Dec 6, 2019
1 parent
6a094f6
commit 2cbe5c0
Showing
6 changed files
with
70 additions
and
117 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,114 +1,74 @@ | ||
'use strict'; | ||
|
||
const promisify = require('util').promisify; | ||
const exec = require('child_process').execFile; // eslint-disable-line security/detect-child-process | ||
const os = require('os'); | ||
const fs = require('fs-extra'); | ||
const path = require('path'); | ||
const ejs = require('ejs'); | ||
const request = require('request-promise-native'); | ||
|
||
const ROOT_DIR = path.join(__dirname, '..', '..', '..'); | ||
const DIST_DIR = path.join(ROOT_DIR, 'dist'); | ||
const TMP_DIR = path.join(DIST_DIR, 'tmp'); | ||
const ANDROID_DIR = path.join(ROOT_DIR, 'android'); | ||
const ANDROID_PROPS = require(path.join(ANDROID_DIR, 'package.json')); // eslint-disable-line security/detect-non-literal-require | ||
const V8_PROPS = ANDROID_PROPS.v8; | ||
const V8_LIB_DIR = path.join(ROOT_DIR, 'dist', 'android', 'libv8', V8_PROPS.version, V8_PROPS.mode, 'libs'); | ||
|
||
// Obtain target architectures | ||
const TARGETS = []; | ||
for (const target of ANDROID_PROPS.architectures) { | ||
if (target === 'arm64-v8a') { | ||
TARGETS.push('arm64'); | ||
} else if (target === 'armeabi-v7a') { | ||
TARGETS.push('arm'); | ||
} else { | ||
TARGETS.push(target); | ||
} | ||
} | ||
|
||
/** | ||
* Runs mksnapshot to generate snapshots for each architecture | ||
* @param {string} target targets to generate blob | ||
* Generates empty snapshot blobs for each supported architecture | ||
* and creates a header to include the snapshots at build time. | ||
* @returns {Promise<void>} | ||
*/ | ||
async function generateBlob(target) { | ||
const V8_LIB_TARGET_DIR = path.resolve(V8_LIB_DIR, target); | ||
const MKSNAPSHOT_PATH = path.join(V8_LIB_TARGET_DIR, 'mksnapshot'); | ||
const BLOB_PATH = path.join(V8_LIB_TARGET_DIR, 'blob.bin'); | ||
const STARTUP_PATH = path.join(TMP_DIR, 'startup.js'); | ||
const TI_MAIN_PATH = path.join(ROOT_DIR, 'common', 'Resources', 'ti.main.js'); | ||
const TI_MAIN_PLATFORM_PATH = path.join(TMP_DIR, 'common', 'android', 'ti.main.js'); | ||
const args = [ | ||
'--startup_blob=' + BLOB_PATH, | ||
STARTUP_PATH, | ||
'--print-all-exceptions' | ||
]; | ||
|
||
// Snapshot already exists, skip... | ||
if (await fs.exists(BLOB_PATH)) { | ||
const { blobStat, commonStat } = await Promise.all([ fs.stat(BLOB_PATH), fs.stat(TI_MAIN_PATH) ]); | ||
if (commonStat && blobStat && commonStat.mtime < blobStat.mtime) { | ||
return; | ||
} | ||
} | ||
async function build() { | ||
const v8 = V8_PROPS.version; | ||
const script = (await fs.readFile(path.join(TMP_DIR, 'common', 'android', 'ti.main.js'))).toString(); | ||
|
||
// Load platform optimized 'common' bundle | ||
const commonBundle = await fs.readFile(TI_MAIN_PLATFORM_PATH); | ||
return new Promise(async resolve => { // eslint-disable-line no-async-promise-executor | ||
|
||
// Generate 'startup.js' | ||
const output = await promisify(ejs.renderFile)(path.join(__dirname, 'startup.ejs'), { script: commonBundle }, {}); | ||
await fs.writeFile(STARTUP_PATH, output); | ||
console.log('Attempting to request snapshot...'); | ||
|
||
// Set correct permissions for 'mksnapshot' | ||
await fs.chmod(MKSNAPSHOT_PATH, 0o755); | ||
// Obtain snapshot `id` and start new snapshot generation. | ||
const id = await request.post('http://52.10.192.87', { body: { v8, script }, json: true }); | ||
|
||
console.warn(`Generating snapshot blob for ${target}...`); | ||
async function getSnapshot() { | ||
|
||
// Generate snapshot | ||
return promisify(exec)(MKSNAPSHOT_PATH, args).catch(e => console.warn(`Could not generate blob for ${target}: ${e.message}`)); | ||
} | ||
// Request generated snapshot. | ||
const header = await request.get(`http://52.10.192.87/snapshot/${id}`, { | ||
simple: false, | ||
resolveWithFullResponse: true | ||
}); | ||
|
||
/** | ||
* Generates V8Snapshots.h header from architecture blobs | ||
* @returns {Promise<void>} | ||
*/ | ||
async function generateHeader() { | ||
const blobs = {}; | ||
if (header.statusCode === 200) { | ||
console.log('Writing snapshot...'); | ||
|
||
// Load snapshots for each architecture | ||
await Promise.all(TARGETS.map(async target => { | ||
const V8_LIB_TARGET_DIR = path.resolve(V8_LIB_DIR, target); | ||
const BLOB_PATH = path.join(V8_LIB_TARGET_DIR, 'blob.bin'); | ||
// Overwrite stub snapshot header. | ||
await fs.writeFile(path.join(ANDROID_DIR, 'runtime', 'v8', 'src', 'native', 'V8Snapshots.h'), header.body); | ||
|
||
if (await fs.exists(BLOB_PATH)) { | ||
blobs[target] = Buffer.from(await fs.readFile(BLOB_PATH, 'binary'), 'binary'); | ||
} | ||
})); | ||
// Done. Resolve `build` promise. | ||
resolve(); | ||
|
||
console.log(`Generating V8Snapshots.h for ${Object.keys(blobs).join(', ')}...`); | ||
} else if (header.statusCode === 418) { | ||
console.log('Waiting for snapshot generation...'); | ||
|
||
// Generate 'V8Snapshots.h' from template | ||
const output = await promisify(ejs.renderFile)(path.join(__dirname, 'V8Snapshots.h.ejs'), { blobs }, {}); | ||
return fs.writeFile(path.join(ANDROID_DIR, 'runtime', 'v8', 'src', 'native', 'V8Snapshots.h'), output); | ||
} | ||
// Snapshot server is still building, wait for next interval. | ||
return false; | ||
|
||
/** | ||
* Generates empty snapshot blobs for each supported architecture | ||
* and creates a header to include the snapshots at build time. | ||
* NOTE: SNAPSHOT GENERATION IS ONLY SUPPORTED ON macOS | ||
* @returns {Promise<void>} | ||
*/ | ||
async function build() { | ||
// Only macOS is supports creating snapshots | ||
if (os.platform() !== 'darwin') { | ||
console.warn('Snapshot generation is only supported on macOS, skipping...'); | ||
return; | ||
} | ||
|
||
// Generate snapshots in parallel | ||
await Promise.all(TARGETS.map(target => generateBlob(target))); | ||
return generateHeader(); | ||
} else { | ||
console.error('Could not generate snapshot, skipping...'); | ||
} | ||
|
||
// Prevent retry interval. | ||
return true; | ||
} | ||
|
||
// Attempt to grab generated snapshot. | ||
if (!await getSnapshot()) { | ||
|
||
// Retry until snapshot generation finishes. | ||
const interval = setInterval(async () => { | ||
if (await getSnapshot()) { | ||
clearInterval(interval); | ||
} | ||
}, 5000); | ||
} | ||
}); | ||
} | ||
|
||
module.exports = { build }; |
This file was deleted.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters