blob: 0cef42db65ef36d324bb500476f408ea27c2033e [file] [log] [blame]
/*
* 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;
}