Browse Source

Linux Installer updates

production
guest 2 years ago
parent
commit
748fd720e2
4 changed files with 620 additions and 346 deletions
  1. 31
    3
      cliverse.js
  2. 250
    343
      index.js
  3. 158
    0
      lin_verse.js
  4. 181
    0
      win_verse.js

+ 31
- 3
cliverse.js View File

@@ -99,14 +99,22 @@ function nodeShellExec() {
return p;
}

var prompt = function(choices, label, defaultchoice){
var prompt = function(choices, label, defaultchoice, selectedchoice){
// prompt accepts either an array or an object as choices.
var choices = choices || [];
defaultchoice = defaultchoice || choices[0] || choices[Object.keys(choices)[0]]
defaultchoice = defaultchoice || choices[0] || selectedchoice || choices[Object.keys(choices)[0]]
var ci = 0;
return this.prompter.ask(
`${label} \n` + Object.keys(choices).map(choice => { var choice_label = isNaN(+choice) ? choice : ((+choice) + 1); return ` ${choice_label}) ${choices[choice]} `}).join('\n') + `\n default ( <= ${ defaultchoice || choices[0]} ) : `
`${label} \n` + Object.keys(choices).map(
choice => {
++ci; var choice_label = isNaN(+choice) ? `${ci}) (${choice})` : ci + ')';
return ` ${choice_label} ${choices[choice]} `
}).join('\n')
+ `\n default ( <= ${ defaultchoice || choices[0]} ) : `
+ `\n selected ( <= ${ selectedchoice || defaultchoice || choices[0]} ) : `
).then(choice => {
// propName = promptable.interpret(propValue)
if(!choice) return selectedchoice;
if(!choice) return defaultchoice || choices[0];
if(choice && isNaN(+choice)) return choice;
return choices[(+choice) - 1];
@@ -138,6 +146,26 @@ var cli = {
return prompt_interface
}
, prompt
, createTask(task, str){

var tasks = {
getTaskCheckExists : (str)=>{
return (command, options) => {
options = options || {}
return () => {
var p = nodeShellExec.apply(null, [str, [command]])
if (options.ignorefailures) {
return p.then(() => { return true }).catch(e => { // Ignore. Not a major error.
return false;
})
}
else return p.then(() => { return true });
}
}
}
}
return tasks[task](str)
}
}

module.exports = cli

+ 250
- 343
index.js View File

@@ -1,6 +1,7 @@
global.env = process.env
global.env.NODE_ENV = global.env.NODE_ENV || 'development'

const fs = require('fs')
var path = require('path');
var utils = require('bbhverse');
var any = utils.any;
@@ -8,7 +9,21 @@ var Tasq = utils.Tasq
var statuslog = utils.Traq
var Traq = utils.Traq
Tasq.addlistener(statuslog.statuslog)
fs.writeFileSync('run.log', ', ' + JSON.stringify( { m : 'Hello'} ), { 'flag': 'a+' })
Tasq.addlistener((e)=>{ fs.writeFileSync('run.log', ', ' + JSON.stringify( e ), { 'flag': 'a+' }) })
var cli = require('./cliverse')
function isWin(){ return /^win/.test(process.platform) }
if(isWin()) {
var win_verse = require('./win_verse')
var shell_verse = win_verse;
}
else {
var lin_verse = require('./lin_verse')
var shell_verse = lin_verse;
}



var nodeShellExec = cli.nodeShellExec;
var chalk = require('chalk')
const homedir = require('os').homedir();
@@ -20,8 +35,8 @@ function sysAddPathVar(addpath){
// }, options)
// powershell $env:Path -split ';'
if (__isElevated) {
return nodeShellExec('Powershell.exe', [
var etask = ()=>{
return nodeShellExec('Powershell.exe', [
`$path = [Environment]::GetEnvironmentVariable('PATH', 'Machine')
$newpath = $path + ';${addpath}'
[Environment]::SetEnvironmentVariable("PATH", $newpath, 'Machine')`
@@ -31,7 +46,10 @@ function sysAddPathVar(addpath){
fs.writeFileSync('run.done', 'error')
})
}
else return op['runas']()
etask.statuslog = statuslog
etask.selectedinstance = selectedinstance
etask.processedArgs = processedArgs
return shell_verse.runElevated(etask)
// var newpath = addpath.split(';');
@@ -132,7 +150,6 @@ const existslink = function(name, cb){
});
}
const existsFolderSync = existsSync;
const fs = require('fs')

const cliargs = utils.cliargs;
const processedArgs = cliargs(process.argv.slice(2));
@@ -283,52 +300,15 @@ var getgitbashtask = (args, onEachError) => { return () => {
return nodeShellExec( `"${gitbash}"`, ['-c', getCmdString(args)], args[2]).catch( onEachError || function(e){ console.error(e) }) }
}

var getTaskCheckExists = (command, options) => {
options = options || {}
return () => {
var p = nodeShellExec.apply(null, ['where', [command]])
if (options.ignorefailures) {
return p.then(() => { return true }).catch(e => { // Ignore. Not a major error.
return false;
})
}
else return p.then(() => { return true });
}
}

var getTaskWithElevation = function(tasdef){
return ()=>{
if (__isElevated) {
return tasdef.elevatedpulltasks().then(()=>{
// PB : TODO -- Every elevation should have its own messaging file. Async writes from multiple processes are a problem here...
fs.writeFileSync('run.done', 'success')
}).catch(e=>{
fs.writeFileSync('run.done', 'failure')
});
}
else {
// PB : TODO -- Rename op['runas'] to 'elevate'

var __runasresult = null;

return op['runas']().then((r) => { return __runasresult = r; })
.catch((e) => {
console.error(e)
})
.finally(() => {
if(__runasresult && !__runasresult.skipped) fs.unlinkSync('run.done')
if (!processedArgs.runas) { return tasdef.regularpulltasks(); }
})
}
}
}
var getTaskCheckExists = shell_verse.getTaskCheckExists
// var getTaskWithElevation = function(tasdef){ return shell_verse.getElevatedTask( tasdef.elevatedpulltasks ) }

var getTaskWithoutElevation = function(tasdef){
return ()=>{
if(!processedArgs.runas) { return tasdef.regularpulltasks(); }
else Promise.resolve(true)
}
}
// var getTaskWithoutElevation = function(tasdef){
// return ()=>{
// if(!processedArgs.runas) { return tasdef.regularpulltasks(); }
// else Promise.resolve(true)
// }
// }

var gitops = {

@@ -386,99 +366,57 @@ var performPull = (repo, branch, repoowner, errHandler) => {
console.log(e)
}


if (exists) {
var branchprint = branch ? ' branch :' + branch : '';
console.log('pulling ' + instanceroot + '/' + repo + branchprint )
return nodeShellExec.apply(null, getPullCmd(repo, branch)).then(() => {
if (__isElevated) {
fs.writeFileSync('run.log', ', ' + JSON.stringify({ repo, success: true }), { 'flag': 'a+' })
}
else statuslog.statuslog(null, repo)
return true;
})
.catch((e) => {
e.repo = repo;
if(errHandler) throw errHandler(e)
if (__isElevated) {
fs.writeFileSync('run.log', ', ' + JSON.stringify(e), { 'flag': 'a+' })
}
else statuslog.statuslog(e);
// console.error(e)
throw e;
})
var task = ()=>{
return nodeShellExec.apply(null, getPullCmd(repo, branch)).then(() => {
return true;
})
}

task.info = { repo }
task.errHandler = errHandler
task.statuslog = statuslog
return shell_verse.runTask( task )
}
else {
console.log('cloning ' + repo)
// PB : TODO -- detect if a clonable repo exists in currentGitAuthUser
return nodeShellExec('git', ['clone', '-c', 'core.symlinks=true', selectedinstance.reposerver + `/${repoowner || defaultRepoOwner}/` + repo + '.git'],
{
inherit: true, shell: true,
env: process.env
, cwd : instanceroot
, runas: processedArgs.runas
}).then(() => {

return nodeShellExec('git', ['config', '--replace-all', 'core.symlinks', true],
{
inherit: true, shell: true,
var task = ()=>{
return nodeShellExec('git', ['clone', '-c', 'core.symlinks=true', selectedinstance.reposerver + `/${repoowner || defaultRepoOwner}/` + repo + '.git'],
{
inherit: true, shell: true,
env: process.env
, cwd: instanceroot + '/' + repo
, runas: processedArgs.runas
, title: `'git', ${['config', '--replace-all', 'core.symlinks', selectedinstance.username].join(' ')}`
})
.then(() => {
if (__isElevated) {
fs.writeFileSync('run.log', ', ' + JSON.stringify({ repo, success: true }), { 'flag': 'a+' })
}
else statuslog.statuslog(null, repo)
})
.catch((e) => {
e.repo = repo;
if (__isElevated) {
fs.writeFileSync('run.log', ', ' + JSON.stringify(e), { 'flag': 'a+' })
}
else statuslog.statuslog(e);
})
})
.catch(e => {
e.repo = repo;
if(errHandler) throw errHandler(e)
if (__isElevated) {
fs.writeFileSync('run.log', ', ' + JSON.stringify(e), { 'flag': 'a+' })
}
else statuslog.statuslog(e);
throw e
})
}
}
, cwd : instanceroot
, runas: processedArgs.runas
}).then(() => {

// PB : TODO -- If we are run from an elevated shell it never moves forward and simply exits.
// -- Currently workaround is to always run from a non-elevated shell.
var __isElevated = null; // We assume non-Elevated until someone evaluates and sets this variable.
var acquireElevationState = () => {
if (__isElevated === null) {
return nodeShellExec("fsutil", ["dirty", "query", "C:"], {
inherit: true
// , shell: true
, stdio: 'ignore'
, env: process.env
, title: `check privileged execution mode using "fsutil dirty query C:"`
}).then((exitcode) => {
console.log('Elevated')
__isElevated = true;
return true;
}).catch(() => {
__isElevated = false;
console.log('Not Elevated');
return false;
});
var task = ()=>{
return nodeShellExec('git', ['config', '--replace-all', 'core.symlinks', true],
{
inherit: true, shell: true,
env: process.env
, cwd: instanceroot + '/' + repo
, runas: processedArgs.runas
, title: `'git', ${['config', '--replace-all', 'core.symlinks', selectedinstance.username].join(' ')}`
})
}
task.info = { repo }
task.errHandler = errHandler
task.statuslog = statuslog
return shell_verse.runTask( task )
})
}
task.info = { repo }
task.errHandler = errHandler
task.statuslog = statuslog
return shell_verse.runTask( task )
}
else return Promise.resolve(__isElevated);
}


var currentGitAuthUser; // nodeShellExec('git', ['config', 'user.email']) ... PB : TODO-- get the current GITEA username
var defaultRepoOwner = 'chess';
var elevatedRunasRepos = null
@@ -499,14 +437,13 @@ var dbForLabel = function (label) {
}

// SAM : TODO Use nodeshellexec where to detect git installation dir
var gitbash = "C:\\Program Files\\Git\\bin\\sh.exe"
var gitbash = shell_verse.getbash()
// var gitbash = "G:\\Installed\\Git\\bin\\sh.exe"
// Relevant git repos
var exludeMergeRepos = [];
var useGitPull = processedArgs.useGitPull || false;
var configPromise = null


var op = {
'h': () => { console.log(elxr.help()); return '-h' }
, 'clean' : () => {
@@ -620,78 +557,6 @@ var op = {
})
})
}
, 'runas': () => {

if(processedArgs.skipelevated) return Promise.resolve({ skipped : true });

console.log('Testing Elevation')

if (__isElevated) {
try {
op[processedArgs.label || processedArgs._[0] || 'undefined'](processedArgs)
}
catch (e) {
console.error('Error Invalid command : ' + e)
fs.writeFileSync('run.done', 'error')
}
finally {
}
}
else {
console.log('Requesting Elevated Privileges');
// Wait for the runas to complete before we read it.
try {
fs.unlinkSync('run.done')
fs.unlinkSync('run.log')
}
catch (e) { } //Ignore

// Find node path to send to hta.
return nodeShellExec('where', ['node']).then(r => {
var namedArgs = [];
console.log('result : ' + JSON.stringify(r))
Object.keys(processedArgs).forEach((v) => { v != '_' ? namedArgs.push('--' + v + '=' + processedArgs[v]) : null; })
// PB : TODO -- Convert all the cli args back to string.
var args = [`${selectedinstance.root}/.elxr/run-${runtimestamp}/windowselevate.hta`].concat(processedArgs._)
namedArgs.length > 0 ? args = args.concat(namedArgs.join(' ')) : null;
args.push('--runas=self');
// args.push('--nodepath=' + r.messages[r.messages.length - 1])
// if (!processedArgs.node_env) args.push('--node_env=' + ENV.NODE_ENV)
// if (processedArgs.debug) args.push('--debug=true') // Enable to debug elevated..
// console.dir(processedArgs._)
// console.dir(namedArgs.join(' '))
console.dir(args)
// throw 'test'

return nodeShellExec('MSHTA', [`"${args.join('" "')}"`]
, {
inherit: true
, shell: true
, env: ENV
, runas: 'self'
, title: `runas`
}
).then(() => {
// runas returned.
try {
// PB : TODO -- Log is comma prefixed. Needs to be proper JSON.
var runaslog = JSON.parse('[ { "success" : true, "result" : "started"}' + fs.readFileSync('run.log', { flags: 'a+' }) + ']');
runaslog.forEach((logEntry) => {
statuslog.statuslog(logEntry.success ? null : logEntry, logEntry)
logEntry.success ? (console.log(['success :' + logEntry.result]), console.log((logEntry.messages || []).join(' '))) : (console.error(['error :' + logEntry.result]), console.error((logEntry.messages || []).join(' ')))
})
}
catch (e) {
// We must have a runas log
statuslog.statuslog(e)
console.error('Run log error probably was not created by runas : ' + e)
}
})
.catch(err => console.error('Elevation failed : ' + err));
})

}
}
, 'push': () => {
if (!processedArgs._[1]) { console.error('push all not supported. Specify repo name'); return }
// init remote bare from local
@@ -1150,14 +1015,17 @@ var op = {
console.log('Running exlr pull : ' + path.dirname(__dirname))

if (!processedArgs.runas) gitRepos.map((def) => performPull(def.repo, def.branch || 'master'))
if (__isElevated) {
var etask = ()=>{
return any(elevatedRunasRepos.map((def) => performPull(def.repo, def.branch || 'master'))).then(() => {
fs.writeFileSync('run.done', 'success')
}).catch(() => {
fs.writeFileSync('run.done', 'error')
})
}
else return op['runas']()
etask.statuslog = statuslog
etask.selectedinstance = selectedinstance
etask.processedArgs = processedArgs
return shell_verse.runElevated(etask)
}

, 'repo-relocate' : function(args){
@@ -1385,7 +1253,7 @@ var op = {
// Usage :
// elxr pull -- Defaults to run config

return elxr.getpulltask(selectedinstance)()
return elxr.getpulltask(selectedinstance)
}
, 'isInstalled': () => {
return nodeShellExec('where', [processedArgs._[1]], { inherit: true }).then(() => {
@@ -1400,10 +1268,10 @@ var op = {
var tasks = []
// tasks.push(op['pull']);
tasks.push(getShellTask.apply(null, ['rm', [instanceroot + '/run.js'], { ignorefailures: true }]))
tasks.push(op['use'])
if (!__isElevated) {
tasks.push(op['npmi'])
}
tasks.push(op['use']) // Will pull repos...
op['npmi'].statuslog = statuslog
tasks.push(shell_verse.getNonElevatedTask(op['npmi'])) // We do not run npm i with elevated privilege for security reasons.

// var tasksdefs = [
// ['elxr', ['pull']]
@@ -1635,7 +1503,7 @@ var op = {
kill(serverPid)
}
, 'model' : () => {
if (__isElevated) {
var etask = ()=>{
var tasks = [
() => {
var p = nodeShellExec('mklink', [ `${processedArgs._[2]}.json`
@@ -1654,7 +1522,10 @@ var op = {
fs.writeFileSync('run.done', 'error')
})
}
else return op['runas']()
etask.statuslog = statuslog
etask.selectedinstance = selectedinstance
etask.processedArgs = processedArgs
return shell_verse.runElevated(etask)
}


@@ -1692,7 +1563,7 @@ var op = {
var promise = new Promise((resolve, reject)=>{
existslink('config', function(err, data){
if(data) {
var p = nodeShellExec('rmdir', ['config'], { inherit: true, shell: true, env: process.env })
var p = shell_verse.removeJuncionOrLink('config')
.then(()=>{resolve(true)})
.catch((err) => { console.log('Ignoring benign error : ' + err); return resolve(true); })
}
@@ -1705,7 +1576,7 @@ var op = {
var promise = new Promise((resolve, reject)=>{
existslink('data', function(err, data){
if(data) {
var p = nodeShellExec('rmdir', ['data'], { inherit: true, shell: true, env: process.env })
var p = shell_verse.removeJuncionOrLink('data')
.then(()=>{resolve(true)})
.catch((err) => { console.log('Ignoring benign error : ' + err); return resolve(true); })
}
@@ -1717,6 +1588,7 @@ var op = {
];
runconfig.NODE_ENV = process.env.NODE_ENV = process.env.NODE_ENV || runconfig.NODE_ENV || 'development';
if (processedArgs._[1] && runconfig.use !== processedArgs._[1]) runconfig.use = processedArgs._[1];
if (!runconfig.use && selectedinstance.instanceName) runconfig.use = selectedinstance.instanceName;
if (!runconfig.use) { throw 'unspecifed use not allowed. Please specify chess instance name.' }
// console.log(process.env.cwd)
fs.writeFileSync(instanceroot + '/run.js', 'module.exports = ' + JSON.stringify(runconfig))
@@ -1821,69 +1693,66 @@ var op = {
// }

return any(tasks).then(() => {
var pr = Promise.resolve(true)
if (!__isElevated) {
pr = op['runas']()
return pr.then(()=>{

//target is the env is we specify in elxr use command. Default is dev
//Switch to target branch
return any(gitRepos.map((repodef) => { return performCheckout({ repo : repodef.repo, branch}).catch(e=>{ console.log(e); }) } ))
// pull or clone target branch
.then(() => {
if(!mergesource || branch === mergesource) return Promise.resolve(true)
return any(gitRepos.map((repo) => performPullAll(repo)))
})
// switch to source branch
.then( () => {
if(!mergesource || branch === mergesource ) return Promise.resolve(true) // Dont do anything if there is no source to merge from.
return any(gitRepos.map((repodef) => performCheckout({ repo : repodef.repo, branch: mergesource})))
})
//Pull on merge source branch
.then( () => {
if(!mergesource || branch === mergesource ) return Promise.resolve(true)
return any(gitRepos.map((repo) => performPullAll(repo)))
})
var task = ()=>{

//target is the env is we specify in elxr use command. Default is dev
//Switch to target branch
.then( () => {
return any(gitRepos.map((repodef) => { return performCheckout({ repo : repodef.repo, branch}).catch(e=>{ console.log(e); }) } ))
// pull or clone target branch
.then(() => {
if(!mergesource || branch === mergesource) return Promise.resolve(true)
return any(gitRepos.map((repo) => performPullAll(repo)))
})
// switch to source branch
.then( () => {
if(!mergesource || branch === mergesource ) return Promise.resolve(true) // Dont do anything if there is no source to merge from.
return any(gitRepos.map((repodef) => performCheckout({ repo : repodef.repo, branch: mergesource})))
})
//Pull on merge source branch
.then( () => {
if(!mergesource || branch === mergesource ) return Promise.resolve(true)
return any(gitRepos.map((repodef) => performCheckout({ repo : repodef.repo, branch})))
return any(gitRepos.map((repo) => performPullAll(repo)))
})
.then( //Merge source branch to target branch
() => {
if(!mergesource || branch === mergesource) return Promise.resolve(true)
return any(gitRepos.map((repo) => performMerge( repo ))).catch(err => { console.error('error in performMerge ' + err) })
})
//Switch to target branch
.then( () => {
if(!mergesource || branch === mergesource ) return Promise.resolve(true)
return any(gitRepos.map((repodef) => performCheckout({ repo : repodef.repo, branch})))
})
.then( //Merge source branch to target branch
() => {
if(!mergesource || branch === mergesource) return Promise.resolve(true)
return any(gitRepos.map((repo) => performMerge( repo ))).catch(err => { console.error('error in performMerge ' + err) })
})
}
else {
tasks = [
task.statuslog = statuslog
var netask = shell_verse.getNonElevatedTask(task)
var eltask = ()=> {
var opts = {
inherit: true, shell: true
, cwd : instanceroot
, env: process.env
}
var tasks = [
() => {
// Use junctions to avoid npm package issues
var p = nodeShellExec('mklink', ['/J', 'config', runconfig.use + '-config' + '-' + process.env.NODE_ENV], {
inherit: true, shell: true
, cwd : instanceroot
, env: process.env
}).catch((e) => { console.error(e) })
var target = runconfig.use + '-' + 'config' + '-' + process.env.NODE_ENV
var p = shell_verse.createJuntionOrLink('config', target, opts)
return p;
}
];
if (processedArgs._[1]) {
tasks = tasks.concat(
[
// if (processedArgs._[1]) {
tasks = tasks.concat( [
() => {
var dataToLink = runconfig.use + '-data' + '-' + process.env.NODE_ENV
if(!existsSync(dataToLink)) dataToLink = runconfig.use + '-data';
var p = nodeShellExec('mklink', ['/J', 'data', dataToLink], {
inherit: true, shell: true
, cwd : instanceroot
, env: process.env
}).catch((e) => { console.error(e) })
var p = shell_verse.createJuntionOrLink('data', dataToLink, opts)
return p;
}
]
)
}
// }
return any(tasks).then(()=>{
// checkout target branch
@@ -1920,9 +1789,15 @@ var op = {
})
})
}
eltask.statuslog = statuslog
eltask.selectedinstance = selectedinstance
eltask.processedArgs = processedArgs
var etask = shell_verse.getElevatedTask(eltask)

}).catch(() => {
fs.writeFileSync('run.done', 'error')
return etask().then( ()=>{ return netask() })

}).catch((e) => {
fs.writeFileSync('run.done', 'error : ' + e)
})

// Antibiotic stewardship program.
@@ -2068,7 +1943,7 @@ var op = {
, 'switch user' : (tousername)=>{ return GIT['switch user'](tousername) }
}

// elxr cli operations
// independent elxr cli operations
var noprerequisites = {
add : true, 'set-url' : true, 'repo-relocate' : true
, remote : true, 'c' : true, 'h' : true
@@ -2202,14 +2077,17 @@ var cmds = {
return p;
}
];
if (__isElevated) {
var etask = ()=>{
return any(tasks).then(() => {
fs.writeFileSync('run.done', 'success')
}).catch(() => {
fs.writeFileSync('run.done', 'error')
})
}
else return op['runas']()
etask.statuslog = statuslog
etask.selectedinstance = selectedinstance
etask.processedArgs = processedArgs
return shell_verse.runElevated(etask)
}
, noprerequisites : true
, privileged : true
@@ -2385,24 +2263,31 @@ var elxr = {
if(def.repo) {
// Single repo case.
if(def.repo.requiresElevation) {
elevatedpulltasks = function() {
var t1 = function() {
return performPull(def.repo).then(() => {
return true;
}).catch((e) => {
console.error(e)
})
}).finally(Traq.finally)
}
return
t1.statuslog = statuslog
t1.selectedinstance = selectedinstance
t1.processedArgs = processedArgs
elevatedpulltasks = shell_verse.getElevatedTask( t1 )
}
else {
var regularpulltasks = function(){
var pendingpulls = [];
pendingpulls.push(performPull(def.repo))
return Promise.all(pendingpulls).finally(Traq.finally)
var t2 = function(){
return performPull(def.repo).then(() => {
return true;
}).catch((e) => {
console.error(e)
}).finally(Traq.finally)
}
t2.statuslog = statuslog
var regularpulltasks = shell_verse.getNonElevatedTask( t2 )
}
if(elevatedpulltasks) return getTaskWithElevation( { elevatedpulltasks, regularpulltasks} )
else return getTaskWithoutElevation({ regularpulltasks})
if(elevatedpulltasks) return elevatedpulltasks //getTaskWithElevation( { elevatedpulltasks, regularpulltasks} )
else return regularpulltasks // getTaskWithoutElevation({ regularpulltasks})
}
// console.log(`-------------------Processing pull for : ${def.repo} ${def.branch}`)
@@ -2432,6 +2317,7 @@ var elxr = {
console.error(e)
})
}
elevatedpulltasks.statuslog = statuslog
}
if(def.repos) {
var regularpulltasks = function(){
@@ -2439,9 +2325,11 @@ var elxr = {
def.repos.forEach((def) => { pendingpulls.push(performPull(def.repo)) })
return Promise.all(pendingpulls).finally(Traq.finally)
}
regularpulltasks.statuslog = statuslog
}
if(elevatedpulltasks) return getTaskWithElevation( { elevatedpulltasks, regularpulltasks} )
else return getTaskWithoutElevation({ regularpulltasks})
// if(elevatedpulltasks) return getTaskWithElevation( { elevatedpulltasks, regularpulltasks} )
// else return getTaskWithoutElevation({ regularpulltasks})
return any([ elevatedpulltasks, regularpulltasks ])
}
}

@@ -2837,8 +2725,8 @@ var __acquireConfig = function (selected, owner, clusternodename, configrepo, er
.catch( (e)=>{
// if(e){
if(Promise.resolve(e) === e) return e;
console.error(e)
throw e; // Not a hard error but we need this for bcontinueonfailure
// console.error(e)
throw e; // Not a hard error but we need this for bcontinueonfailure as we still want to stop on firstsuccess.
// }
})
}
@@ -2907,7 +2795,7 @@ var __acquireData = function (selected, owner, clusternodename, datarepo, errHan
.catch( (e)=>{
// if(e){
if(Promise.resolve(e) === e) return e;
console.error(e)
// console.error(e)
throw e; // Not a hard error but we need this for bcontinueonfailure
// }
})
@@ -2982,6 +2870,7 @@ var __default = ((name, options)=>{
server : `${options.reposerver}`, user : '${options.username}', path : ``, get url(){ return `${this.server}/${this.user}/${this.path}`} // fetch
}
, 'origin-public' : {
// export GIT_SSL_NO_VERIFY=true
server : `https://git.bbh.org.in`, user : 'chess', path : ``, get url(){ return `${this.server}/${this.user}/${this.path}`} // fetch
, push : {
server : `${options.reposerver}`, user : `${options.username}`, path : ``, get url(){ return `${this.server}/${this.user}/${this.path}`}
@@ -3264,6 +3153,7 @@ var __interactive_prompts = function( target, choices, promptsfilter ){
: `
, choices : []
, defaultchoice : 'c'
, selectedchoice : target.runchoice
, interpret : function(choice){
var interpret_map = {
d : function(){
@@ -3273,8 +3163,12 @@ var __interactive_prompts = function( target, choices, promptsfilter ){
target.reposerver = 'https://git.bbh.org.in'
}
, n : function() { processedArgs._[0] = 'i' }
, i : function() { processedArgs._[0] = 'i' }
, i : function() {
processedArgs._[0] = 'i'
// processedArgs._[1] = target.instanceName || processedArgs._[1] || 'chess';
}
, c : async function() {
// this here will always be the target.
Object.defineProperty(this, 'cmd', getPromptableAsyncPropDescriptor('cmd', {
label : `Enter cmd :
p) pull
@@ -3292,26 +3186,40 @@ var __interactive_prompts = function( target, choices, promptsfilter ){
, h : function() { console.log(elxr.help()); process.exit() } // PB : TODO -- Why do we need log.
, q : function() { process.exit() }
}
var __interpreter = interpret_map['c']

if(Promise.resolve(choice) === choice){
return choice.then( resolvedchoice => {
return (interpret_map[choice] || interpret_map['c']).call(target)
})
}
else return Promise.resolve( (interpret_map[choice] || interpret_map['c']).call(target) )

// var __interpreter = interpret_map[choice] || interpret_map['c']
// if(!choice) return interpret_map['c']() // This should not happen prompter should always give us a default choice.
if(interpret_map[choice]) __interpreter = interpret_map[choice];
// if(interpret_map[choice]) __interpreter = interpret_map[choice];
return __interpreter.call(target)
// return __interpreter.call(target)
}
}
, instanceName : { label : `Enter Instance Name ( <= ${target.instanceName || 'chess'} ) : `
, choices : choices['instanceName'], defaultchoice : 'chess'}
, choices : choices['instanceName'], defaultchoice : 'chess'
, selectedchoice : target.instanceName
}
, instanceType : { label : `Enter Instance Type ( <= ${target.instanceType || 'development'} ) : `
, choices : choices['instanceType'], defaultchoice : 'development'}
, choices : choices['instanceType'], defaultchoice : 'development'
, selectedchoice : target.instanceType
}
, reposerver : { label : `Enter Repo Url ( <= ${target.reposerver || 'https://git.bbh.org.in'} ) : `
, choices : choices['reposerver'], defaultchoice : 'https://git.bbh.org.in'}
, choices : choices['reposerver'], defaultchoice : 'https://git.bbh.org.in'
, selectedchoice : target.reposerver
}
, get username() { return { label : `Enter User Id for ${target.reposerver} ( <= ${target.username || 'chess'} ) : `
, choices : choices['username'], defaultchoice : 'chess'} }
, choices : choices['username'], defaultchoice : 'chess', selectedchoice : target.username } }
, get password() { return { label : `Enter Password for ${target.username} @ ${target.reposerver} ( <= ${target.password || ''} ) : `
, choices : choices['password'], defaultchoice : '***'} }
, choices : choices['password'], defaultchoice : '***', selectedchoice : target.password } }
, get email() { return { label : `Enter Email for ${target.username} @ ${target.reposerver} ( <= ${target.email || ''} ) : `
, choices : choices['email'], defaultchoice : 'guest@bbh.org.in'} }
, choices : choices['email'], defaultchoice : 'guest@bbh.org.in', selectedchoice : target.email } }

}

@@ -3454,7 +3362,7 @@ var prerequisites = [
,
{
shellcmd: 'node',
name : 'ndoe',
name : 'node',
url: 'https://nodejs.org/dist/v14.16.0/node-v14.16.0-x64.msi'
, installer: 'node-v14.16.0-x64.msi'
, installcmd: ['MSIEXEC.exe', ['/i'
@@ -3500,7 +3408,7 @@ function verifyAndInstallPrerequisites() {
var getPromptableAsyncPropDescriptor = function(propName, promptable){
return {
get (){
return cli.prompt( promptable.choices, promptable.label, promptable.defaultchoice ).then(propValue => {
return cli.prompt( promptable.choices, promptable.label, promptable.defaultchoice, promptable.selectedchoice ).then(propValue => {
var asyncprop = Promise.resolve(propValue)
if(promptable.interpret){
@@ -3973,16 +3881,20 @@ function initinstances(selected_overrides) {
}
// Override sequence.
// __default, chessinstances[current_run], instanceName-config-development, cliargs, interactve_promts
// PB : TODO -- Undefined keys are overriding and deleting values. We should not allow that.
// This is ordinary utils.assign behavior. The key should not exist as undefined in the override.
if(selected_overrides.node_env === undefined) delete selected_overrides.node_env
selectedinstance = utils.assign(
chessinstances[instanceName][node_env]
, clioverrides
, selected_overrides
, selected_overrides
// , __interactive_prompts -- Cant just override. Also need selectedinstance to be ready...
);

// chessinstances[instanceName] = chessinstances[instanceName] || {}
// chessinstances[instanceName][node_env] = chessinstances[instanceName][node_env] || {}
// if(!selectedinstance.repos || selectedinstance.instanceName) {
// // Brand New.
// selectedinstance = Object.assign( __default, selectedinstance )
@@ -4021,37 +3933,28 @@ var maintask = () => {
return prerequisites.git.verifyAndInstall().then(()=>{
var e = { message : 'verifyAndInstall', success : true}
var inittasks = []
var commantask = () => { preworkerconfig(); return elxrworker(true) }
if(!detection_state.localInstanceDetected) {
var specifictask = ()=>{ return createInstance(selectedinstance) }
var commantask = () => { preworkerconfig(); return elxrworker(true) }
if(!__isElevated) {
}
else {
specifictask = ()=>{ Promise.resolve(true) }
}
inittasks.push(specifictask().then( commantask ))
var t1 = ()=>{ return createInstance(selectedinstance) };
t1.statuslog = statuslog
var specifictask = shell_verse.getNonElevatedTask(t1)
}
else {
var specifictask = ()=>{ return acquireConfig(selectedinstance) }
var commantask = () => { preworkerconfig(); return elxrworker(true) }
if(!__isElevated) {
}
else {
specifictask = ()=>{ return Promise.resolve(true) }
}
inittasks.push( specifictask().catch((err) => {
e = err;
console.error('Chosen cofiguraton failed or not found. Fix config and rerun or chose another.')
console.error(err)
}).then( commantask )
// .finally(()=>{
// fs.writeFileSync('run.log', ', ' + JSON.stringify({ error: e.message }), { 'flag': 'a+' })
// if(!e.success) fs.writeFileSync('run.done', 'error');
// // return process.exit()
// }))
)
var t2 = ()=>{ return acquireConfig(selectedinstance) };
t2.statuslog = statuslog
var specifictask = shell_verse.getNonElevatedTask(t2)
}
inittasks.push( specifictask().catch((err) => {
e = err;
console.error('Chosen cofiguraton failed or not found. Fix config and rerun or chose another.')
console.error(err)
}).then( commantask )
// .finally(()=>{
// fs.writeFileSync('run.log', ', ' + JSON.stringify({ error: e.message }), { 'flag': 'a+' })
// if(!e.success) fs.writeFileSync('run.done', 'error');
// // return process.exit()
// }))
)
return any(inittasks)
})
@@ -4184,6 +4087,7 @@ var startElxr = function() {
var cmdinstance = cmds[clioverrides.cmd]
var cmdprompts = cmdinstance.getPossiblePrompts()
selectedinstance.node_env ? selectedinstance.node_env : selectedinstance.node_env = clioverrides.node_env
// PB : TODO -- Most recent should be at the tip ! at index 0 so utils.reverseassign is required !!!
selectedinstance = utils.assign( ...detectedinstanceoptions.slice(-2), promptkeys )
// promptkeys = utils.assign(promptkeys, clioverrides)
@@ -4247,7 +4151,7 @@ var startElxr = function() {
return elxrworker()
}

if(!__isElevated) {
var neTask = ()=>{
ensureDirectoryExistence(`${selectedinstance.root}/.elxr/${__ALIAS__STAMP__}`)
// collect garbage
return dirs( (dir)=>{
@@ -4273,36 +4177,39 @@ var startElxr = function() {
}
else return true
})
.then(()=>{
if (!skipprerequisites && !__isElevated || processedArgs.forceprereqs && !__isElevated ) mainTasks.push(verifyAndInstallPrerequisites);
mainTasks.push(maintask)
return any(mainTasks);
})
}
else {
if (!skipprerequisites && !__isElevated || processedArgs.forceprereqs && !__isElevated ) mainTasks.push(verifyAndInstallPrerequisites);
}
neTask.statuslog = statuslog
shell_verse.getNonElevatedTask( neTask )()
var commonTask = ()=>{
verifyAndInstallPrerequisites.statuslog = statuslog
if((!skipprerequisites || processedArgs.forceprereqs)) mainTasks.push(verifyAndInstallPrerequisites);
mainTasks.push(maintask)
return any(mainTasks);
}
return commonTask()
})
}

detectInstanceRoot.then(()=>{
var cmdobj = cmds[clioverrides.cmd]
return Promise.all((cmdobj.requires || []).map( (r) => utils.promisify(null, r) ) ).then(()=>{
if(cmdobj.independentcmd) {
if(cmdobj.requiresElevation) {
return acquireElevationState().then(() => {
cmdobj.cmdFn() })
// PB : TODO -- In windows if we are run from an elevated shell we never move forward and simply exits !?.
// -- Currently workaround in windows is to always run from a non-elevated shell.
shell_verse.acquireElevationState().then((elevationstate) => {
return detectInstanceRoot.then(()=>{
var cmdobj = cmds[clioverrides.cmd]
return Promise.all((cmdobj.requires || []).map( (r) => utils.promisify(null, r) ) ).then(()=>{
if(cmdobj.independentcmd) {
if(cmdobj.requiresElevation) {
return cmdobj.cmdFn()
}
else return cmdobj.cmdFn()
}
else return cmdobj.cmdFn()
}
else return acquireElevationState().then(() => {
return startElxr()
else return startElxr()
})
.catch(e => {
if(typeof e === 'symbol') console.log('error : ' + 'symbol')
else console.log('error : ' + e)
})
})
.catch(e => {
console.log('error ')
})
})


+ 158
- 0
lin_verse.js View File

@@ -0,0 +1,158 @@
const fs = require('fs')

var cli = require('./cliverse')
var nodeShellExec = cli.nodeShellExec;

// PB : TODO -- linux prerequistes.
// npm i -g nodemon
// sudo apt install python2
// sudo apt install build-essential
// sudo apt install -y make

// phantomjs": "^2.1.7
// "sass": "^1.32.7",
// "node-sass": "^5.0.0",
// "ember-cli-sass": "^10.0.1",
// "gulp-sass": "^4.1.0",

// ember-searchable-select
// ember-cli-sass
// ember-cp-validatations
// ember-cli-yuidoc
// yuidoc-ember-theme

// chess-server-lib/server
// java

// client
// export NODE_OPTIONS=--openssl-legacy-provider

// elixir-client npmi
// elixir-client/chess-client-lib npmi
// crossfilter2

var __isElevated = null;
var shell_verse = {
// getCommonTask is agnostic of whether we are running in an elevated shell or not. It runs in either case.
getCommonTask( taskToRun ){ return ()=>{ return shell_verse.runTask(taskToRun) }}
, runTask : ( taskToRun ) => {
if (__isElevated) return shell_verse.elevatedRunner()
else return shell_verse.runNonElevated( taskToRun )
}

, elevatedRunner( taskToRun ){
try {
var __runasresult = null;
return taskToRun().then((r)=>{
// PB : TODO -- Every elevation should have its own messaging file. Async writes from multiple processes are a problem here...
fs.writeFileSync('run.log', ', ' + JSON.stringify( { info : taskToRun.info, success: true }), { 'flag': 'a+' })
fs.writeFileSync('run.done', 'success') // PB : TODO -- This should be done conditionally if we are running inproc.
return __runasresult = r;
})
.catch((e) => {
fs.writeFileSync('run.log', ', ' + JSON.stringify(e), { 'flag': 'a+' })
fs.writeFileSync('run.done', 'failure')
console.error(e)
})
.finally(() => {
if(__runasresult && !__runasresult.skipped) fs.unlinkSync('run.done')
})
}
catch (e) {
console.error('Error Invalid command : ' + e)
fs.writeFileSync('run.done', 'error')
}
finally {
}
}
, getElevatedTask : function( taskToRun ){ return ()=>{ return shell_verse.runElevated(taskToRun) }}
, runElevated : ( taskToRun ) => {
// Let shell_verse decide whether to Elevate Out of Proc or In Proc
// taskToRun by default is the launched command and args. Specially in windows out of proc.
// taskToRun = taskToRun || (()=>{ return op[processedArgs.label || processedArgs._[0] || 'undefined'](processedArgs) })

if(taskToRun.processedArgs.skipelevated) return Promise.resolve({ skipped : true });


if (__isElevated) {
return shell_verse.elevatedRunner(taskToRun)
}
else {
console.log('Requesting Elevated Privileges');
// requesteElevation is acutally request elevation and run. Both In Proc and Out of Proc.
// Linux doesnt require elevation for most commands...
return shell_verse.requestElevation(shell_verse.elevatedRunner, taskToRun)
}
}

, getNonElevatedTask : function( taskToRun ){ return ()=>{ return shell_verse.runNonElevated(taskToRun) } }
, runNonElevated : ( taskToRun ) => {
// Let shell_verse decide whether to Elevate Out of Proc or In Proc
if(__isElevated) {
return Promise.resolve( new Error('Cannot Run Task in Elevated Mode.') )
}
else {
// taskToRun by default is the launched command and args.
// taskToRun = taskToRun || (()=>{ return op[processedArgs.label || processedArgs._[0] || 'undefined'](processedArgs) })

return taskToRun().then(r=>{
taskToRun.statuslog.statuslog(null, taskToRun.info /*repo*/ )
return r;
}).catch((e) => {
e.info = taskToRun.info;
if(taskToRun.errHandler) throw taskToRun.errHandler(e)
taskToRun.statuslog.statuslog(e);
// console.error(e)
throw e;
}).finally(()=>{})
}
}
, isElevated : ()=>{
return acquireElevationState().then( ()=>{
shell_verse.isElevated = () => {
return Promise.resolve(__isElevated)
}
return shell_verse.isElevated()
})
}
// , isElevationOutOfProc : ()=>{ return true }

, acquireElevationState : () => {
return Promise.resolve(false).then(( elevationstate ) => {
__isElevated ? console.log('Elevated') : console.log('Not Elevated')
__isElevated = elevationstate;
}).catch(() => {
__isElevated = false;
console.log('Not Elevated');
}).finally(()=>{
shell_verse.acquireElevationState = ()=> Promise.resolve(__isElevated);
shell_verse.isElevated = () => { return Promise.resolve(__isElevated)}
return __isElevated;
})
}

, getTaskCheckExists : cli.createTask('getTaskCheckExists', 'which')

, getbash : ()=>{ return "sh" }

, createJuntionOrLink : (dirOrFile, target, opts)=>{
return nodeShellExec('ln', ['-s', target, dirOrFile], opts).catch((e) => { console.error(e) })
}

, removeJuncionOrLink : ( junctionOrLink )=>{
return nodeShellExec('rm', [junctionOrLink], { inherit: true, shell: true, env: process.env })
}

, requestElevation(elevatedRunner, taskToRun) {
// PB : TODO -- Most linking cmds in linux may not need elevation like in windows.
// However returning true here is pseudo and will break cases where real elevation is required in linux. We need to refactor to reimplement
// this with sudo and change all calles to use ony where required.
return elevatedRunner(taskToRun);
}
}

module.exports = shell_verse

+ 181
- 0
win_verse.js View File

@@ -0,0 +1,181 @@
const fs = require('fs')

var cli = require('./cliverse')
var nodeShellExec = cli.nodeShellExec;

var __isElevated = null;
var shell_verse = {
// getCommonTask is agnostic of whether we are running in an elevated shell or not. It runs in either case.
getCommonTask( taskToRun ){ return ()=>{ return shell_verse.runTask(taskToRun) }}
, runTask : ( taskToRun ) => {
if (__isElevated) return shell_verse.elevatedRunner()
else return shell_verse.runNonElevated( taskToRun )
}

, elevatedRunner( taskToRun ){
try {
var __runasresult = null;
return taskToRun().then((r)=>{
// PB : TODO -- Every elevation should have its own messaging file. Async writes from multiple processes are a problem here...
fs.writeFileSync('run.log', ', ' + JSON.stringify( { info : taskToRun.info, success: true }), { 'flag': 'a+' })
fs.writeFileSync('run.done', 'success') // PB : TODO -- This should be done conditionally if we are running inproc.
return __runasresult = r;
})
.catch((e) => {
fs.writeFileSync('run.log', ', ' + JSON.stringify(e), { 'flag': 'a+' })
fs.writeFileSync('run.done', 'failure')
console.error(e)
})
.finally(() => {
if(__runasresult && !__runasresult.skipped) fs.unlinkSync('run.done')
})
}
catch (e) {
console.error('Error Invalid command : ' + e)
fs.writeFileSync('run.done', 'error')
}
finally {
}
}
, getElevatedTask : function( taskToRun ){ return ()=>{ return shell_verse.runElevated(taskToRun) }}
, runElevated : ( taskToRun ) => {
// Let shell_verse decide whether to Elevate Out of Proc or In Proc
// taskToRun by default is the launched command and args. Specially in windows out of proc.
// taskToRun = taskToRun || (()=>{ return op[processedArgs.label || processedArgs._[0] || 'undefined'](processedArgs) })

if(taskToRun.processedArgs.skipelevated) return Promise.resolve({ skipped : true });


if (__isElevated) {
return shell_verse.elevatedRunner(taskToRun)
}
else {
console.log('Requesting Elevated Privileges');
// requesteElevation is acutally request elevation and run. Both In Proc and Out of Proc.
// Linux doesnt require elevation for most commands...
return shell_verse.requestElevation(shell_verse.elevatedRunner, taskToRun)
}
}

, getNonElevatedTask : function( taskToRun ){ return ()=>{ return shell_verse.runNonElevated(taskToRun) } }
, runNonElevated : ( taskToRun ) => {
// Let shell_verse decide whether to Elevate Out of Proc or In Proc
if(__isElevated) {
return Promise.resolve( new Error('Cannot Run Task in Elevated Mode.') )
}
else {
// taskToRun by default is the launched command and args.
// taskToRun = taskToRun || (()=>{ return op[processedArgs.label || processedArgs._[0] || 'undefined'](processedArgs) })

return taskToRun().then(r=>{
taskToRun.statuslog.statuslog(null, taskToRun.info /*repo*/ )
return r;
}).catch((e) => {
e.info = taskToRun.info;
taskToRun.statuslog.statuslog(e);
if(taskToRun.errHandler) throw taskToRun.errHandler(e)
// console.error(e)
throw e;
}).finally(()=>{})
}
}

, isElevated : ()=>{
return acquireElevationState().then( ()=>{
shell_verse.isElevated = () => {
return Promise.resolve(__isElevated)
}
return shell_verse.isElevated()
})
}

// , isElevationOutOfProc : ()=>{ return true }
, acquireElevationState : () => {
return nodeShellExec("fsutil", ["dirty", "query", "C:"], {
inherit: true
// , shell: true
, stdio: 'ignore'
, env: process.env
, title: `check privileged execution mode using "fsutil dirty query C:"`
}).then((exitcode) => {
console.log('Elevated')
__isElevated = true;
}).catch(() => {
__isElevated = false;
console.log('Not Elevated');
}).finally(()=>{
shell_verse.acquireElevationState = ()=> Promise.resolve(__isElevated);
shell_verse.isElevated = () => { return Promise.resolve(__isElevated)}
return __isElevated;
})
}
, getTaskCheckExists : cli.createTask('getTaskCheckExists', 'where')

, getbash : ()=>{ return "C:\\Program Files\\Git\\bin\\sh.exe" }

, createJuntionOrLink : (dirOrFile, target, opts) =>{
return nodeShellExec('mklink', ['/J', dirOrFile, target], opts).catch((e) => { console.error(e) })
}
, removeJuncionOrLink : ( junctionOrLink )=>{
return nodeShellExec('rmdir', [junctionOrLink], { inherit: true, shell: true, env: process.env })
}

, requestElevation(elevatedRunner, taskToRun) {
var processedArgs = taskToRun.processedArgs, selectedinstance = taskToRun.selectedinstance , statuslog = taskToRun.statuslog
// Wait for the runas to complete before we read it.
try {
fs.unlinkSync('run.done')
fs.unlinkSync('run.log')
}
catch (e) { } //Ignore

// Find node path to send to hta.
return nodeShellExec('where', ['node']).then(r => {
var namedArgs = [];
console.log('result : ' + JSON.stringify(r))
Object.keys(processedArgs).forEach((v) => { v != '_' ? namedArgs.push('--' + v + '=' + processedArgs[v]) : null; })
// PB : TODO -- Convert all the cli args back to string.
var args = [`${selectedinstance.root}/.elxr/run-${runtimestamp}/windowselevate.hta`].concat(processedArgs._)
namedArgs.length > 0 ? args = args.concat(namedArgs.join(' ')) : null;
args.push('--runas=self');
// args.push('--nodepath=' + r.messages[r.messages.length - 1])
// if (!processedArgs.node_env) args.push('--node_env=' + ENV.NODE_ENV)
// if (processedArgs.debug) args.push('--debug=true') // Enable to debug elevated..
// console.dir(processedArgs._)
// console.dir(namedArgs.join(' '))
console.dir(args)
// throw 'test'

return nodeShellExec('MSHTA', [`"${args.join('" "')}"`]
, {
inherit: true
, shell: true
, env: ENV
, runas: 'self'
, title: `runas`
}
).then(() => {
// runas returned.
try {
// PB : TODO -- Log is comma prefixed. Needs to be proper JSON.
var runaslog = JSON.parse('[ { "success" : true, "result" : "started"}' + fs.readFileSync('run.log', { flags: 'a+' }) + ']');
runaslog.forEach((logEntry) => {
statuslog.statuslog(logEntry.success ? null : logEntry, logEntry)
logEntry.success ? (console.log(['success :' + logEntry.result]), console.log((logEntry.messages || []).join(' '))) : (console.error(['error :' + logEntry.result]), console.error((logEntry.messages || []).join(' ')))
})
}
catch (e) {
// We must have a runas log
statuslog.statuslog(e)
console.error('Run log error probably was not created by runas : ' + e)
}
})
.catch(err => console.error('Elevation failed : ' + err));
})
}
}

module.exports = shell_verse

Loading…
Cancel
Save