Files
react-native-code-push/scripts/generateBundledResourcesHash.js
Geoffrey Goh 3ab1fa0a10 feedback
2016-02-26 17:50:32 -08:00

92 lines
3.9 KiB
JavaScript

/*
* This script generates a hash of all the React Native bundled assets and writes it into
* into the APK. The hash in "updateCheck" requests to prevent downloading an identical
* update to the one already present in the binary.
*
* It first creates a snapshot of the contents in the resource directory by creating
* a map with the modified time of all the files in the directory. It then compares this
* snapshot with the one saved earlier in "recordFilesBeforeBundleCommand.js" to figure
* out which files were generated by the "react-native bundle" command. It then computes
* the hash for each file to generate a manifest, and then computes a hash over the entire
* manifest to generate the final hash, which is saved to the APK's assets directory.
*/
var crypto = require("crypto");
var fs = require("fs");
var path = require("path");
var getFilesInFolder = require("./getFilesInFolder");
var CODE_PUSH_FOLDER_PREFIX = "CodePush";
var CODE_PUSH_HASH_FILE_NAME = "CodePushHash.json";
var HASH_ALGORITHM = "sha256";
var TEMP_FILE_PATH = path.join(require("os").tmpdir(), "CodePushResourcesMap.json");
var resourcesDir = process.argv[2];
var jsBundleFilePath = process.argv[3];
var assetsDir = process.argv[4];
var resourceFiles = [];
getFilesInFolder(resourcesDir, resourceFiles);
var oldFileToModifiedTimeMap = require(TEMP_FILE_PATH);
var newFileToModifiedTimeMap = {};
resourceFiles.forEach(function(resourceFile) {
newFileToModifiedTimeMap[resourceFile.path.substring(resourcesDir.length)] = resourceFile.mtime;
});
var bundleGeneratedAssetFiles = [];
for (var newFilePath in newFileToModifiedTimeMap) {
if (!oldFileToModifiedTimeMap[newFilePath] || oldFileToModifiedTimeMap[newFilePath] < newFileToModifiedTimeMap[newFilePath].getTime()) {
bundleGeneratedAssetFiles.push(newFilePath);
}
}
var manifest = [];
if (bundleGeneratedAssetFiles.length) {
bundleGeneratedAssetFiles.forEach(function(assetFile) {
// Generate hash for each asset file
var readStream = fs.createReadStream(resourcesDir + assetFile);
var hashStream = crypto.createHash(HASH_ALGORITHM);
readStream.pipe(hashStream)
.on("error", function(error) {
throw error;
})
.on("finish", function() {
hashStream.end();
var buffer = hashStream.read();
var fileHash = buffer.toString("hex");
manifest.push(CODE_PUSH_FOLDER_PREFIX + assetFile.replace(/\\/g, "/") + ":" + fileHash);
if (manifest.length === bundleGeneratedAssetFiles.length) {
// Generate hash for JS bundle
readStream = fs.createReadStream(jsBundleFilePath);
hashStream = crypto.createHash(HASH_ALGORITHM);
readStream.pipe(hashStream)
.on("error", function(error) {
throw error;
})
.on("finish", function() {
hashStream.end();
var buffer = hashStream.read();
var fileHash = buffer.toString("hex");
manifest.push(CODE_PUSH_FOLDER_PREFIX + "/" + path.basename(jsBundleFilePath) + ":" + fileHash);
manifest = manifest.sort();
var finalHash = crypto.createHash(HASH_ALGORITHM)
.update(JSON.stringify(manifest))
.digest("hex");
var savedResourcesManifestPath = assetsDir + "/" + CODE_PUSH_HASH_FILE_NAME;
fs.writeFileSync(savedResourcesManifestPath, finalHash);
});
}
});
});
}
fs.unlinkSync(TEMP_FILE_PATH);