UNPKG

pwabuilder-edgeextension

Version:
156 lines (128 loc) 5.63 kB
var fs = require('fs'), os = require('os'), path = require('path'), url = require('url'); var archiver = require('archiver'), cloudappx = require('cloudappx-server'), Q = require('q'), request = require('request'); var pwabuilderLib = require('pwabuilder-lib'); var CustomError = pwabuilderLib.CustomError, log = pwabuilderLib.log; var serviceEndpoint = 'http://cloudappx.azurewebsites.net'; // Quick sanity check to ensure that the placeholder parameters in the manifest // have been replaced by the user with their publisher details before generating // a package. function validateManifestPublisherDetails(appFolder, shouldSign, callback) { var manifestPath = path.join(appFolder, 'appxmanifest.xml'); return Q.nfcall(fs.readFile, manifestPath, 'utf8').then(function (data) { if (shouldSign) { return; } var packageIdentityPlaceholders = /<Identity.*(Name\s*=\s*"INSERT-YOUR-PACKAGE-IDENTITY-NAME-HERE"|Publisher\s*=\s*"CN=INSERT-YOUR-PACKAGE-IDENTITY-PUBLISHER-HERE")/g; var publisherDisplayNamePlaceholder = /<PublisherDisplayName>\s*INSERT-YOUR-PACKAGE-PROPERTIES-PUBLISHERDISPLAYNAME-HERE\s*<\/PublisherDisplayName>/g; if (packageIdentityPlaceholders.test(data) || publisherDisplayNamePlaceholder.test(data)) { return Q.reject(new Error('The application manifest is incomplete. Register the app in the Windows Store to obtain the Package/Identity/Name, \nPackage/Identity/Publisher, and Package/Properties/PublisherDisplayName details. \nThen, use this information to update the corresponding placeholders in the appxmanifest.xml file before \ncreating the App Store package.')); } }) .catch(function (err) { return Q.reject(new CustomError('The specified path does not contain a valid app manifest file.', err)); }) .nodeify(callback); } function invokeCloudAppX(name, appFolder, outputFilePath, operation, callback) { var deferred = Q.defer(); var archive = archiver('zip'); var zipFile = path.join(os.tmpdir(), name + '.zip'); var output = fs.createWriteStream(zipFile); var endPointValue = '/v3/' + operation; archive.on('error', function (err) { deferred.reject(err); }); archive.pipe(output); archive.directory(appFolder, name); archive.finalize(); var operationUrl = url.resolve(process.env.CLOUDAPPX_SERVICE_ENDPOINT || serviceEndpoint, endPointValue); output.on('close', function () { var options = { method: 'POST', url: operationUrl, encoding: 'binary' }; log.debug('Invoking the CloudAppX service...'); var req = request.post(options, function (err, resp, body) { if (err) { return deferred.reject(err); } if (resp.statusCode !== 200) { return deferred.reject(new Error('Failed to create the package. The CloudAppX service returned an error - ' + resp.statusMessage + ' (' + resp.statusCode + '): ' + body)); } fs.writeFile(outputFilePath, body, { 'encoding': 'binary' }, function (err) { if (err) { return deferred.reject(err); } fs.unlink(zipFile, function (err) { if (err) { return deferred.reject(err); } return deferred.resolve(); }); }); }); req.form().append('xml', fs.createReadStream(zipFile)); }); return deferred.promise.nodeify(callback); } var makeAppx = function (appFolder, outputPath, shouldSign, callback) { var name = 'edgeExtension'; var appxFile = path.join(outputPath, name + '.appx'); return validateManifestPublisherDetails(appFolder, shouldSign).then(function () { // call sign endpoint or traditional if (shouldSign === true) { log.debug('Invoking the CloudAppX service to generate a signed APPX package'); return invokeCloudAppX(name, appFolder, appxFile, 'buildsigned'); } else { return Q.fcall(cloudappx.makePri, appFolder, appFolder) .thenResolve({ 'dir': appFolder, 'name': name, 'out': outputPath, 'shouldSign': shouldSign }) .then(cloudappx.makeAppx) .catch(function () { log.debug('Unable to create the package locally. Invoking the CloudAppX service instead...'); return invokeCloudAppX(name, appFolder, appxFile, 'build'); }); } }) .nodeify(callback); }; var makePri = function (appFolder, outputPath, callback) { var name = 'resources'; return Q.fcall(cloudappx.makePri, appFolder, outputPath).catch(function () { log.info('Unable to index resources locally. Invoking the CloudAppX service instead...'); var priFile = path.join(outputPath, name + '.pri'); return invokeCloudAppX(name, appFolder, priFile, 'makepri'); }) .nodeify(callback); }; var makeWeb = function (appFolder, outputPath, callback) { var deferred = Q.defer(); var archive = archiver('zip'); var packagePath = path.join(outputPath, 'windows.web'); var output = fs.createWriteStream(packagePath); var manifestPath = path.resolve(appFolder, '../manifest.json'); archive.on('error', function (err) { deferred.reject(err); }); archive.pipe(output); output.on('close', function() { deferred.resolve(); }); archive.glob('**/*.*', { cwd: appFolder, ignore: 'appxmanifest.xml' }); archive.file(manifestPath, { name: 'manifest.json' }); archive.finalize(); return deferred.promise.nodeify(callback); }; module.exports = { makeAppx: makeAppx, makePri: makePri, makeWeb: makeWeb };