percli
Version:
peregrine-cms cli tool
461 lines (420 loc) • 14.1 kB
JavaScript
const fs = require('fs')
const http = require('http')
const { spawn, spawnSync } = require('child_process')
const open = require('open')
const { fetch } = require('./fetch')
const maven = require('maven')
const os = require('os')
const path = require('path')
var inquirer = require('inquirer')
let port = 8080
function whatSling() {
if(fs.existsSync('out/sling-11.jar')) {
return 11;
} else if(fs.existsSync('out/sling-9.jar')) {
return 9;
} else {
throw('only supporting sling-9.jar and sling-11.jar');
}
}
/**
* Starts up the sling instance
* @param {string} type - the run mode(standalone, author, publish)
*/
function startSling(type, debug) {
console.log('startSling')
require('./available.js')(['java'], function(success, tech) {
if(success) {
const sling = whatSling();
if(sling === 9 && parseInt(tech.java.version[0]) >= 11) {
console.log(`sling-9 needs java-8`);
process.exit(0);
}
const args = [];
if(parseInt(tech.java.version[0]) >= 11) {
args.push('-XX:+UseParallelGC');
args.push('--add-opens=java.desktop/com.sun.imageio.plugins.jpeg=ALL-UNNAMED');
args.push('--add-opens=java.base/sun.net.www.protocol.jrt=ALL-UNNAMED');
args.push('--add-opens=java.naming/javax.naming.spi=ALL-UNNAMED');
args.push('--add-opens=java.xml/com.sun.org.apache.xerces.internal.dom=ALL-UNNAMED');
args.push('--add-opens=java.base/java.lang=ALL-UNNAMED ');
args.push('--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED');
args.push('--add-opens=java.base/java.net=ALL-UNNAMED');
args.push('-Dnashorn.args=--no-deprecation-warning');
}
args.push( '-jar');
args.push(`out/sling-${sling}.jar`);
args.push('start');
if(debug) {
args.unshift("-agentlib:jdwp=transport=dt_socket,address=30303,server=y,suspend=n")
args.unshift("-Xdebug")
}
if(type === 'standalone') {
// do nothing
} else if(type === 'author') {
args.push("-Dsling.run.modes=author,notshared")
} else if(type === 'publish') {
args.push("-Dsling.run.modes=publish,notshared")
args.push("-p")
args.push("8180")
port = 8180
}
console.log('#CMD# java',args.join(' '))
const child = spawn('java', args, {
detached: true,
shell: true,
stdio: 'inherit'
})
child.unref()
} else {
console.log('java is not installed, please go to https://adoptopenjdk.net/ and download Java8 LTS or Java11 LTS');
throw('install java');
}
});
}
/**
* Stops the sling instance
*/
function stopSling() {
const sling = whatSling();
const args = ['-jar',`out/sling-${sling}.jar`, 'stop'];
console.log('#CMD#',args.join(' '))
const child = spawn('java', args, {
detached: true,
shell: true,
stdio: 'inherit'
})
child.unref()
}
/**
* Checks if the sling instance is running by calling a GET to the system console
* @param {boolean} errorWhenRunning - true/false on whether to throw error when running
*/
function checkIfRunning(errorWhenRunning = true, path = '/system/console/bundles.json') {
return new Promise((resolve, reject) => {
http.get('http://admin:admin@localhost:'+port+path, function(res) {
let rawData = '';
res.on('data', chunk => { rawData += chunk; });
res.on('end', () => {
try {
passed = false;
if(path.endsWith('.json')) {
let status = JSON.parse(rawData).s
if(status[3] === 0 && status[4] === 0) {
passed = true;
}
console.log('status', status)
} else {
console.log('status code of',path,res.statusCode)
passed = res.statusCode < 400
}
if(passed) {
if(errorWhenRunning) {
reject()
} else {
resolve()
}
} else {
if(errorWhenRunning) {
resolve()
} else {
reject()
}
}
} catch (e) {
console.error(e.message);
reject()
}
})
}).on('error', e => {
if(e.code === 'ECONNREFUSED') {
if(errorWhenRunning) {
resolve()
} else {
reject()
}
}
//console.error(`Got error: ${JSON.stringify(e)}`);
})
})
}
/**
* Calls a timeout for the given amount of time
* @param {number} time - the amount of time
*/
async function wait(time){
return new Promise((resolve, reject) => {
setTimeout(resolve, time)
})
}
/**
* Checks if sling has started by calling the checkIfRunning() function every 1000ms
*/
async function waitUntilRunning() {
let stopped = true
while(stopped){
await wait(1000)
await checkIfRunning(false)
.then( () => {
stopped = false
console.log('sling already running')
})
.catch( () => {
console.log('waiting for sling to start');
})
}
stopped = true
while(stopped) {
await wait(1000)
await checkIfRunning(false, '/')
.then( () => {
stopped = false
console.log('sling responding with good status')
})
.catch( () => {
console.log('waiting for sling to start');
})
}
}
/**
* Gets the pcms settings file path
* @return {String} the file path
*/
function getSettings() {
return path.join(os.homedir(), '.pcms-servers')
}
/**
* Lists all peregrine-cms servers on this computer
*/
function listServers() {
const settingsFile = getSettings()
if(fs.existsSync(settingsFile)) {
console.log()
console.log('[INFO] list of all peregrine-cms servers on this computer')
const settings = JSON.parse(fs.readFileSync(getSettings()).toString())
console.log()
settings.forEach( (server) => {
console.log('-', server.name, server.path)
})
} else {
console.error('[ERROR] no settings file found at', settingsFile)
}
}
/**
* Adds a peregrine-cms server
* @param {String} name - the server name
* @param {String} path - the server path
*/
function addServer(name, path) {
const settingsFile = getSettings()
let settings = []
if(fs.existsSync(settingsFile)) {
console.log('list of all peregrine-cms servers on this computer')
settings = JSON.parse(fs.readFileSync(getSettings()).toString())
}
settings.push( {name: name, path: path})
fs.writeFileSync(settingsFile, JSON.stringify(settings, true, 2))
}
/**
* Gets the server path
* @param {String} name - the server name
* @return {string} the sever path
*/
function getPathForServer(name) {
const settingsFile = getSettings()
let settings = []
if(fs.existsSync(settingsFile)) {
settings = JSON.parse(fs.readFileSync(getSettings()).toString())
for(let i = 0; i < settings.length; i++) {
if(settings[i].name === name) {
return settings[i].path
}
}
}
}
/**
* Checks if the given path is registered in the settings
* @param {string} path - the path
* @return {boolean} true/false if the path is registered
*/
function pathRegistered(path) {
const settingsFile = getSettings()
let settings = []
if(fs.existsSync(settingsFile)) {
settings = JSON.parse(fs.readFileSync(getSettings()).toString())
for(let i = 0; i < settings.length; i++) {
if(settings[i].path === path) {
return true
}
}
}
}
/**
* Prompts the user to enter a server name
* @param {string} path - the path
* @return {string} the server name that the user entered
*/
function promptAddServer(path) {
const prompt = inquirer.createPromptModule();
const question = [
{
type: 'input',
name: 'servername',
message: 'Register a server name to this path:',
validate: nameRegistered
}
]
return new Promise(resolve => {
prompt(question).then(answer => resolve(answer['servername']))
})
}
/**
* Validates that the server name is not already registered
* @param {string} name - the name
* @return {string} true if the name is not registered, otherwise the failed validation message
*/
const nameRegistered = name => {
const settingsFile = getSettings()
let settings = []
if(fs.existsSync(settingsFile)) {
settings = JSON.parse(fs.readFileSync(getSettings()).toString())
for(let i = 0; i < settings.length; i++) {
if(settings[i].name === name) {
return ' This name has already been registered. Please choose a different name.'
}
}
}
return true
}
module.exports = {
/**
* Starts up the peregrine instance
* @param {String} type - the run mode
* @return {string} a new promise
*/
startPeregrine(type,debug) {
return new Promise((resolve, reject) => checkIfRunning().then(() => {
console.log('sling is not running')
let started = true;
try {
startSling(type,debug)
} catch(error) {
started = false;
reject(error);
}
if(started) {
waitUntilRunning().then((msg) => {
console.log(msg)
setTimeout( () => { open("http://localhost:"+port+"/") }, 2000);
resolve()
})
}
}).catch((error) => {
if(!error) {
console.log('found an already running sling instance, aborting start')
}
reject(error)
})
)
},
/**
* Stops the peregrine instance
* @return {string} a new promise
*/
stopPeregrine() {
return new Promise((resolve, reject) => {
stopSling()
}).catch(() => {
reject()
})
},
/**
* Gets the package list
* @return {string} the package list
*/
getPackageList(sling) {
const packagesUrl = sling === 9 ? 'https://vagrant.headwire.com/peregrine/packages.txt' :
'https://vagrant.headwire.com/peregrine/sling11/packages.txt';
return new Promise( (resolve, reject) => {
fetch(packagesUrl)
.then(res => { resolve(res.data.split('\n').filter(line => line.length > 0)) })
.catch(err => { reject(`failed to download ${packagesUrl}`) })
})
},
/**
* Installs the file to the sling instance
* @param {String} mvn - the maven object
* @param {string} line - the line
* @return {string} the maven execution
*/
installFile: async function(mvn, line, port) {
// return mvn.execute(
// ['io.wcm.maven.plugins:wcmio-content-package-maven-plugin:install'],
// {
// "sling.port": port,
// "vault.file": "out/" + line,
// "vault.serviceURL": "http://localhost:"+port+"/bin/cpm/package.service.html"
// }
// )
return spawnSync( 'node', ['"'+__dirname+'/../node_modules/@peregrinecms/slingpackager/bin/slingpackager"', 'upload','-i', '--server', 'http://localhost:'+port, 'out/'+line] ,{
shell: true,
stdio: 'inherit'
})
},
/**
* Installs the packages
* @param {array} packages - the packages
*/
installPackages: async function(packages, port){
let mvn = maven.create()
for(let i = 0; i < packages.length; i++) {
await module.exports.installFile(mvn, packages[i], port)
}
},
/**
* Sets the port
* @param {string} port - the port
*/
setPort: function(newPort) {
port = newPort
},
/**
* Lists all peregrine-cms servers on this computer
*/
listServers: function() {
listServers()
},
/**
* Adds a peregrine-cms server
* @param {String} name - the server name
* @param {String} path - the server path
*/
addServer: function(name, path) {
addServer(name, path)
},
/**
* Gets the server path
* @param {string} name - the server name
* @return {string} the path for the server
*/
getPathForServer(name) {
return getPathForServer(name)
},
/**
* Checks if the given path is registered in the settings
* @param {string} path - the path
* @return {boolean} true/false if the path is registered
*/
pathRegistered(path) {
return pathRegistered(path)
},
/**
* Prompts the user to enter a server name
* @param {string} path - the path
* @return {string} the server name that the user entered
*/
promptAddServer: function(path) {
return promptAddServer(path)
},
wait: wait
}