cmds/package.js (178 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 archiver = require('archiver') const fs = require('fs') const path = require('path') const xmlbuilder = require('xmlbuilder'); const logger = require('../utils/consoleLogger') const configFile = 'slingpackager.config.js' exports.command = 'package <folder>' exports.desc = 'create a package' exports.builder = { server: { hidden: true }, user: { hidden: true }, retry: { hidden: true }, destination: { alias: 'd', describe: 'Package destination directory. Defaults to current directory.' }, config: { alias: 'c', describe: 'Package configuration/properties. Package properties.xml and package name are generated from this. ' + 'If this option is missing slingpackage will search for slingpackager.config.js in the parent directories.' } } exports.handler = (argv) => { logger.init(argv); if(isValid(argv.folder)) { archive(argv); } } function archive(argv) { var config = loadConfig(argv); if(config === undefined) { logger.error(configFile,'not found in the project.'); throw "Unable to find configuration " + configFile; } var destDir = process.cwd(); if(argv.destination && fs.existsSync(argv.destination) && fs.statSync(argv.destination).isDirectory()) { destDir = argv.destination } var packagePath = path.join(destDir, packageName(config)); logger.log('package folder', argv.folder, 'as', packagePath); var output = fs.createWriteStream(packagePath); var archive = archiver('zip'); archive.on('error', (err) => { throw err }); archive.pipe(output); var jcrRoot = path.join(argv.folder, 'jcr_root'); archive.directory(jcrRoot, 'jcr_root', { name: 'jcr_root' }); var metainf = path.join(argv.folder, 'META-INF'); archive.directory(metainf, 'META-INF', { name: 'META-INF' }); addConfigDefaults(config); var xml = propertiesXMLFromJson(config); logger.debug('Writing generated META-INF/vault/properties.xml'); logger.debug(xml); archive.append(xml, {name: 'META-INF/vault/properties.xml'}); archive.finalize(); } function isValid(dir) { if(!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) { console.log(dir,"does not exist or is not a folder."); return false; } var jcrRoot = path.join(dir, 'jcr_root'); if(!fs.existsSync(jcrRoot) || !fs.statSync(jcrRoot).isDirectory()) { console.log(jcrRoot,"does not exist or is not a folder."); return false; } var metainf = path.join(dir, 'META-INF'); if(!fs.existsSync(metainf) || !fs.statSync(metainf).isDirectory()) { console.log(metainf,"does not exist or is not a folder."); return false; } return true; } function propertiesXMLFromJson(json) { var properties = json['vault-properties']; var entries = properties['entry']; var xml = xmlbuilder.create('properties'); for(var elem in properties) { if(elem != 'entry') { xml.ele(elem, properties[elem]); } } for(var entry in entries) { xml.ele('entry', {'key': entry}, entries[entry]); } xml.end({ pretty: true}); var xmlProlog = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n' + '<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">\n'; return xmlProlog + xml.toString({ pretty: true}); } function addConfigDefaults(config) { var properties = config['vault-properties']; var entries = properties['entry']; if(!entries['createdBy']) { entries['createdBy'] = 'slingpackager'; } if(!entries['acHandling']) { entries['acHandling'] = 'IGNORE'; } if(!entries['allowIndexDefinitions']) { entries['allowIndexDefinitions'] = false; } if(!entries['requiresRoot']) { entries['requiresRoot'] = false; } if(!entries['path']) { entries['path'] = '/etc/packages/' + entries['group'] + '/' + entries['name'] + '-' + entries['version'] + '.zip'; } } function packageName(config) { var properties = config['vault-properties']; var entries = properties['entry']; var name = entries['name']; var group = entries['group']; var version = entries['version']; if(!name || !group || !version) { logger.error(configFile, "is missing one or more of the required entries for 'name', 'group' or 'version' to generate a package."); throw "Config is missing one or more of the required entries for 'name', 'group' or 'version' to generate a package." } return name+"-"+version+".zip"; } function loadConfig(argv) { var configFile if(argv.config) { if(fs.existsSync(argv.config) && fs.statSync(argv.config).isFile) { configFile = argv.config; } else { logger.warn('Unable to find configuration file',argv.config); } } if(configFile === undefined) { configFile = findConfigFile(argv.folder); } if(configFile != undefined) { var config = requireConfig(configFile); if(config === undefined) { config = JSON.parse(fs.readFileSync(configFile, 'utf8')); } logger.debug(JSON.stringify(config)); return config; } else { logger.error('Unable to find configuration file either in parent folders or provided via --config option.'); } return undefined; } function requireConfig(configFile) { try { return require(configFile); } catch(err) {} return undefined; } function findConfigFile(dirPath) { logger.debug('Looking for', configFile, 'in', dirPath); var filePath = path.join(dirPath, configFile); if(fs.existsSync(filePath)) { logger.debug('Found', filePath); return filePath; } else { var parentPath = path.resolve(dirPath, '..'); if(parentPath && parentPath != dirPath) { return findConfigFile(parentPath); } } logger.warn('Unable to find',configFile); return undefined; }