utils/composumpackager.js (301 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ const request = require('request') const fs = require('fs') const path = require('path') const logger = require('./consoleLogger'); const listEndpoint = "/bin/cpm/package.list.json"; const uploadEndpoint = "/bin/cpm/package.upload.json"; const deleteEndpoint = "/bin/cpm/package.delete.json"; const installEndpoint = "/bin/cpm/package.install.json"; const uninstallEndpoint = "/bin/cpm/package.uninstall.json"; const check = (url, username, password, callback) => { let serviceURL = url + '/bin/cpm/package.json'; logger.debug('Checking Composum Package Manager.'); logger.debug('Service call: ', serviceURL); request.get({ url: serviceURL }, (error, response, body) => { if (response && response.statusCode === 200) { callback(true); } else { callback(false) } }).auth(username, password); } const list = (url, username, password, maxRetry) => { logger.log('Listing packages on', url); listPackages(url, username, password, '', maxRetry); } const upload = (url, username, password, packagePath, install, maxRetry) => { logger.log('Uploading package', packagePath, 'on', url); let serviceURL = url + uploadEndpoint + "?force=true"; let post = callPostService({serviceURL, username, password, maxRetry}, (error, json) => { if(error) { logger.error('Unable to upload package', packagePath); logger.error(error); process.exit(1); } else { logger.log(json.status) logger.debug(JSON.stringify(json)); if(install) { installPackage(url, username, password, json.path, maxRetry); } } }); post.form().append('file', fs.createReadStream(packagePath)); logger.debug(JSON.stringify(post.toJSON())); } const deletePackage = (url, username, password, package, maxRetry) => { logger.log('Deleting package', package, 'on', url); let serviceURL = url + deleteEndpoint + package; let req = callService({serviceURL, method: 'DELETE', username, password, maxRetry}, (error, json) => { if(error) { logger.error('Unable to delete package', package); logger.error(error); process.exit(1); } else { logger.log(json.status); logger.debug(JSON.stringify(json)); } }); logger.debug(JSON.stringify(req.toJSON())); } const install = (url, username, password, package, maxRetry) => { installPackage(url, username, password, package, maxRetry); } const uninstall = (url, username, password, package, maxRetry) => { logger.log('Uninstalling package', package, 'on', url); let post = postJob({url, username, password, package, maxRetry}, 'uninstall', (error, result) => { if(error) { logger.error('Unable to uninstall package', package); logger.error(error); process.exit(1); } else { if(result && (typeof(result) === 'string') && result.startsWith('Unable')) { logger.error(result); process.exit(1); } } }); } const build = (url, username, password, package, maxRetry) => { logger.log('Building package', package, 'on', url); let post = postJob({url, username, password, package, maxRetry}, 'assemble', (error, result) => { if(error) { logger.error('Unable to build package', package); logger.error(error); process.exit(1); } else { if(result && (typeof(result) === 'string') && result.startsWith('Unable')) { logger.error(result); process.exit(1); } } }); } const download = (url, username, password, destination, package, maxRetry) => { logger.log('Downloading package', package, 'from', url, 'to', destination); let serviceURL = url + "/bin/cpm/package.download.zip" + package; downloadPackage({url, username, password, destination, package, maxRetry}); } const getName = () => { return 'Composum Package Manager'; } function installPackage(url, username, password, package, maxRetry) { logger.log('Installing package', package, 'on', url); let post = postJob({url, username, password, package, maxRetry}, 'install', (error, result) => { if(error) { logger.error('Unable to uninstall package', package); logger.error(error); process.exit(1); } }); } function downloadPackage(data) { if(data.filePath) { data.serviceURL = data.url + "/bin/cpm/package.download.zip" + data.package; callGetService(data, (error, response) => { if(error) { logger.error("Unable to download package."); process.exit(1); } else { if(fs.existsSync(data.filePath)) { var stats = fs.statSync(data.filePath); logger.log("Package downloaded."); logger.log(stats.size + " " + data.filePath); } } }, true).pipe(fs.createWriteStream(data.filePath));; } else { data.serviceURL = data.url + listEndpoint; let req = callGetService(data, (error, response) => { if(error) { logger.error("Unable to download package."); process.exit(1); } else { var packages = response.children ? response.children : response; for (var i = 0; i < packages.length; i++) { if(packages[i].type === 'package' && isPackage(packages[i], data.package)) { let fileName = packages[i].file; let filePath = path.join(data.destination, fileName); data.filePath = filePath; data.package = packages[i].path; downloadPackage(data); return; } } logger.error("Unable to download package. Package " + data.package + " is not found on server."); } }, false); logger.debug("Request: ", JSON.stringify(req.toJSON(), undefined, ' ')); } } function isPackage(packJson, name) { if(packJson.id === name || packJson.name === name || packJson.path === name) { return true; } else { return packJson.definition.name === name; } } function listPackages(url, username, password, path, maxRetry) { var serviceURL = url + listEndpoint + path; let req = callGetService({serviceURL, username, password, maxRetry}, (error, json) => { if(error) { logger.error("Unable to list packages."); logger.error(error); process.exit(1); } else { var packages = json.children ? json.children : json; displayPackages(url, username, password, packages); } }); logger.debug(JSON.stringify(req.toJSON())); } function displayPackages(url, username, password, packages) { for (var i = 0; i < packages.length; i++) { if(packages[i].type === 'package') { logger.log('name=' + packages[i].definition.name + ' group=' + packages[i].definition.group + ' version=' + packages[i].definition.version + ' path=' + packages[i].id); } else if(packages[i].type === 'folder') { // This is not needed on Sling11 as list service returns complete list of packages. listPackages(url, username, password, packages[i].path); } } } function postJob(data, operation, callback) { data.serviceURL = data.url + '/bin/cpm/core/jobcontrol.job.json'; let post = callPostService(data, (error, json) => { if(json && json['slingevent:eventId']) { setTimeout(() => { getJobOutput(data.url, data.username, data.password, json['slingevent:eventId'], callback) },100); } else { callback(error, json); } }); var form = post.form(); form.append('event.job.topic', 'com/composum/sling/core/pckgmgr/PackageJobExecutor'); form.append('_charset_', 'UTF-8'); form.append('operation', operation); form.append('reference', data.package); return post; } function callGetService(data, callback, isDownload=false) { data.method = "GET"; return callService(data, callback, isDownload); } function callPostService(data, callback) { data.method = "POST"; var post = callService(data, callback); logger.debug('POST:', JSON.stringify(post.toJSON(), undefined, ' ')); return post; } function callService(data, callback, isDownload=false) { if(data.retryCount === undefined) { data.retryCount = 0; if(data.maxRetry === undefined) { data.maxRetry = 10; } } logger.debug(data.retryCount + '. Service call: ', data.serviceURL); let req = request({ url: data.serviceURL, method: data.method }, (error, response, body) => { var statusCodeLine = (response === undefined) ? "" : "Response: " + response.statusCode + " : " + response.statusMessage; logger.debug(statusCodeLine); if (error) { if(data.retryCount < data.maxRetry) { data.retryCount++; callService(data, callback); } else { logger.error(error); callback(error + " " + statusCodeLine, undefined); } return; } if (response && response.statusCode === 200) { if (body) { if(isDownload) { callback(undefined, response); } else { var json = JSON.parse(body); logger.debug('Response:', JSON.stringify(json, undefined, ' ')); callback(undefined, json); } return; } else { logger.debug("Respons has no body."); } } if(data.retryCount < data.maxRetry) { data.retryCount++; callService(data, callback); } else { callback("Error calling service " + data.serviceURL, undefined); } return; }).auth(data.username, data.password); return req; } function getJobOutput(url, username, password, eventId, callback, jobState) { var requestData = {url: url + "/bin/cpm/core/jobcontrol.outfile.txt/" + eventId}; if(jobState === undefined || jobState === "ACTIVE" || jobState === "QUEUED") { requestData.url = url + "/bin/cpm/core/jobcontrol.job.json/" + eventId; } request.get(requestData, (error, response, body) => { var statusCodeLine = (response === undefined) ? "" : "Response: " + response.statusCode + " : " + response.statusMessage; logger.debug(statusCodeLine); if(error) { logger.error(error); } else if(body) { if(body.trim().startsWith("{")) { var json = JSON.parse(body); logger.debug('Response:', JSON.stringify(json, undefined, ' ')); if(json["jobState"]) { setTimeout(()=>{ getJobOutput(url, username, password, eventId, callback, json["jobState"]); }, 100); return; } } logger.log(body.trim()); } else if (response && response.statusCode != 200) { if(callback) { callback('Package manager job service failed. '+statusCodeLine, undefined); } else { logger.error('Package manager job service failed.', statusCodeLine); process.exit(1); } } if(callback) { callback(error, body); } }).auth(username, password); } module.exports = { check, list, upload, deletePackage, install, uninstall, build, download, getName }