| [VI]Version: {version} - built on {date}[/VI] Your local downloads for this instance | 
| // console.dir(args[2]) | // console.dir(args[2]) | ||||
| console.log('nodeshellexec ::: ') | console.log('nodeshellexec ::: ') | ||||
| console.log(`${args[0]} ${args[1].join(' ') }`) | |||||
| console.log(`${args[0]} ${args[1].join(' ') } ${args[args.length-1].cwd}`) | |||||
| const child = spawn(...args); | const child = spawn(...args); | ||||
| var p = new Promise(function(resolve, reject){ | var p = new Promise(function(resolve, reject){ | ||||
| process.stdout.write( chunk ) | process.stdout.write( chunk ) | ||||
| }); | }); | ||||
| child.on('error', (chunk) => { success = false; messages.push(chunk); /* console.error('e: ' + chunk) */ | child.on('error', (chunk) => { success = false; messages.push(chunk); /* console.error('e: ' + chunk) */ | ||||
| console.log('Error exit not handled.') | |||||
| } ); | |||||
| console.error('Error exit not handled.') | |||||
| }); | |||||
| child.stderr.on('data', (chunk) => { | child.stderr.on('data', (chunk) => { | ||||
| if(messages.join('').indexOf('fatal: not a git repository') > -1) opts.haserrors = true; | if(messages.join('').indexOf('fatal: not a git repository') > -1) opts.haserrors = true; | ||||
| messages.push(chunk); | messages.push(chunk); | 
| // }).then(Tasq.then).catch(Tasq.catch) | // }).then(Tasq.then).catch(Tasq.catch) | ||||
| // }) | // }) | ||||
| var bowerRepos = [{ repo : 'client'}]; | |||||
| var bowerRepos = [{ repo : 'elixir-client'}]; | |||||
| var bowertasks = []; | var bowertasks = []; | ||||
| bowerRepos.forEach(repodef => { | bowerRepos.forEach(repodef => { | ||||
| bowertasks.push(() => { | bowertasks.push(() => { | 
| // }).then(Tasq.then).catch(Tasq.catch) | // }).then(Tasq.then).catch(Tasq.catch) | ||||
| // }) | // }) | ||||
| var bowerRepos = [{ repo : 'client'}]; | |||||
| var bowerRepos = [{ repo : 'elixir-client'}]; | |||||
| var bowertasks = []; | var bowertasks = []; | ||||
| bowerRepos.forEach(repodef => { | bowerRepos.forEach(repodef => { | ||||
| bowertasks.push(() => { | bowertasks.push(() => { | 
| // models\api\v1 | |||||
| const fs = require('fs') | |||||
| var path = require('path'); | |||||
| const { readdir } = require("fs").promises | |||||
| var verse = require('../serververse'); | |||||
| const fswalk = verse.fs.walk | |||||
| var path = require('path'); | |||||
| const Rx = require('rxjs'); | |||||
| const cliargs = verse.cliargs; | |||||
| const processedArgs = cliargs(process.argv.slice(2)); | |||||
| // console.dir(processedArgs) | |||||
| // console.dir(Rx) | |||||
| // https://github.com/coolaj86/node-walk | |||||
| // PB : TODO -- convert to an input json config. | |||||
| var outputfile = processedArgs._[0]; // ../elixir-client/physio/linkclient.bat | |||||
| var startdir = processedArgs._[1]; // ../elixir-client/physio-1/app/models/api/v1 | |||||
| var inprefix = processedArgs._[2]; // '../../../../../elixir-client/client/' | |||||
| if(!inprefix) inprefix = '..\\client\\' | |||||
| var unprefix = processedArgs._[3]; // ../elixir-client/physio-1/ | |||||
| if(!unprefix) unprefix = '../elixir-client/physio-1/' | |||||
| var outprefix = processedArgs._[4]; // '../../../../../elixir-client/physio/' | |||||
| if(!outprefix) outprefix = '' | |||||
| var fswalkoptions = {} // all files recurscively | |||||
| // var fswalkoptions = { includerootdir : true, includedirectories : true, expand : true } // example walk and output everything. | |||||
| // (unprefix, outprefix) | |||||
| // console.log(path.normalize(unprefix)) | |||||
| const writeStream = ( fs.createWriteStream(outputfile) ) | |||||
| fswalk.call( fswalkoptions, startdir ).then( s => { | |||||
| s.subscribe( entry => { | |||||
| // var matches = /.*?data.*/.exec(utils.fs.direntToFullname(entry)) | |||||
| // if(matches) console.dir( matches[0] ) // Filters can be done on the stream itself.. | |||||
| var i = entry | |||||
| var pathnodes = i.path.replace( path.normalize(unprefix), '' ).split('\\') | |||||
| var relative = Array(pathnodes.length) | |||||
| writeStream.write( '\nmklink ' + (entry.isDirectory() ? ' /D ' : ' ') + i.path.replace( path.normalize(unprefix), outprefix ) + ' ' | |||||
| + relative.join('..\\') + inprefix + i.path.replace( path.normalize(unprefix), outprefix ) | |||||
| ) | |||||
| // console.dir( entry ) | |||||
| } | |||||
| ) | |||||
| // ; s.unsubscribe() | |||||
| }) | 
| p_round: p_round, | p_round: p_round, | ||||
| g_round: g_round, | g_round: g_round, | ||||
| escapeRegExp(string) { | escapeRegExp(string) { | ||||
| return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string | |||||
| return string.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); // $& means the whole matched string | |||||
| } | } | ||||
| , getTZOffsetMilliseconds : (()=>{ | , getTZOffsetMilliseconds : (()=>{ | ||||
| // }).then(Tasq.then).catch(Tasq.catch) | // }).then(Tasq.then).catch(Tasq.catch) | ||||
| // }) | // }) | ||||
| var bowerRepos = [{ repo : 'client'}]; | |||||
| var bowerRepos = [{ repo : 'elixir-client'}]; | |||||
| var bowertasks = []; | var bowertasks = []; | ||||
| bowerRepos.forEach(repodef => { | bowerRepos.forEach(repodef => { | ||||
| bowertasks.push(() => { | bowertasks.push(() => { | 
| var downloadtasks = []; | var downloadtasks = []; | ||||
| var installtasks = []; | var installtasks = []; | ||||
| // var prereqfilter = ['nvm'] | |||||
| var prereqfilter = ['*'] | |||||
| prerequisites.forEach(function(preq) { | prerequisites.forEach(function(preq) { | ||||
| WScript.Echo(all) | |||||
| if(!all && preq.optional) return | |||||
| var p = preq.exists().then(function(exists) { | |||||
| if (exists && !preq.forceinstall) console.log( preq.shellcmd + ' exists'); | |||||
| else { | |||||
| console.log('----------------------------') | |||||
| console.log(exists) // PB : ??? Boolean true becomes -1 ??? | |||||
| console.log('----------------------------') | |||||
| if(!exists) console.log(preq.shellcmd + ' is not installed'); | |||||
| else console.log(preq.shellcmd + ' is installed but forceinstall was specifed so re-installing'); | |||||
| return preq.preinstallsteps().then(function(){ | |||||
| // console.log(' task.install : ' + preq.install) | |||||
| installtasks.push( function(){ return preq.install() } ); | |||||
| // WScript.Echo('FFFFFFFFFFFFF : ' + preq.shellcmd) | |||||
| for(var p=0; p < prereqfilter.length; p++) { | |||||
| if( preq.shellcmd === prereqfilter[p] || prereqfilter[p] === '*' ) { | |||||
| WScript.Echo(all) | |||||
| if(!all && preq.optional) return | |||||
| var p = preq.exists().then(function(exists) { | |||||
| if (exists && !preq.forceinstall) console.log( preq.shellcmd + ' exists'); | |||||
| else { | |||||
| console.log('----------------------------') | |||||
| console.log(exists) // PB : ??? Boolean true becomes -1 ??? | |||||
| console.log('----------------------------') | |||||
| if(!exists) console.log(preq.shellcmd + ' is not installed'); | |||||
| else console.log(preq.shellcmd + ' is installed but forceinstall was specifed so re-installing'); | |||||
| return preq.preinstallsteps().then(function(){ | |||||
| // console.log(' task.install : ' + preq.install) | |||||
| installtasks.push( function(){ return preq.install() } ); | |||||
| }) | |||||
| } | |||||
| }) | }) | ||||
| // .then(function(res){ console.log( 'preinstallsteps ' + res)}); | |||||
| downloadtasks.push( p ) | |||||
| } | } | ||||
| }) | |||||
| // .then(function(res){ console.log( 'preinstallsteps ' + res)}); | |||||
| downloadtasks.push( p ) | |||||
| } | |||||
| }); | }); | ||||
| // console.log('downloadtasks') | // console.log('downloadtasks') | ||||
| // console.dir(downloadtasks[0]) | // console.dir(downloadtasks[0]) | ||||
| // return any([any(steps), any(prompts)]) | // return any([any(steps), any(prompts)]) | ||||
| } | } | ||||
| } | } | ||||
| , { | |||||
| shellcmd: 'nvm', | |||||
| url: 'https://github.com/coreybutler/nvm-windows/releases/download/1.1.11/nvm-setup.exe' | |||||
| , installer: 'nvm-setup.exe' | |||||
| , installcmd: ['cmd', ['/c', 'start', | |||||
| '/WAIT', downloadsdir + '/' + 'nvm-setup.exe' | |||||
| , '/VERYSILENT' | |||||
| // , '/MERGETASKS=!runcode' // This is required only for vscode... | |||||
| ]] | |||||
| , install : install | |||||
| , exists : exists | |||||
| , preinstallsteps: function() { | |||||
| var self = this; | |||||
| console.log('Node preinstall steps') | |||||
| // console.log(this.installcmd) | |||||
| // console.log(path.normalize(downloadsdir + '/' + 'node-v14.17.3-x64.msi')) | |||||
| var steps = []; | |||||
| steps.push( | |||||
| function(){ | |||||
| if (!existsSync(downloadsdir + '/' + self.installer)) { | |||||
| return nodeShellExec(selectedinstance.root + '/.elxr/run-' + runtimestamp + '/download.bat', ['"' + self.url + '"', downloadsdir + '/' + self.installer] | |||||
| , { waitmsg : 'downloading '+ self.shellcmd +' please wait' }) | |||||
| } | |||||
| else { | |||||
| console.log(self.installer + ' Already exits Download skipped.') | |||||
| return Promise.resolve(true) | |||||
| } | |||||
| } | |||||
| ) | |||||
| return any(steps) | |||||
| // return any([any(steps), any(prompts)]) | |||||
| } | |||||
| } | |||||
| , { | , { | ||||
| shellcmd: 'python' | shellcmd: 'python' | ||||
| , optional : true | , optional : true | ||||
| promises.push(verifyAndInstallPrerequisites()) | promises.push(verifyAndInstallPrerequisites()) | ||||
| startPromises(); | startPromises(); | ||||
| } | |||||
| } | |||||
| // Open JDK | |||||
| // https://objects.githubusercontent.com/github-production-release-asset-2e65be/602574963/cd0ac1ad-740d-4616-aa96-157ac2e79a60?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAVCODYLSA53PQK4ZA%2F20240117%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240117T055737Z&X-Amz-Expires=300&X-Amz-Signature=4c0ce9303027a065fed291a107ff0a5f7d7782a828f077873bd5111c8e6fa0f0&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=602574963&response-content-disposition=attachment%3B%20filename%3DOpenJDK21U-jdk_x64_windows_hotspot_21.0.1_12.msi&response-content-type=application%2Foctet-stream | |||||
| // JRE for runtime | |||||
| // https://my.visualstudio.com/Downloads?q=Visual%20Studio%202022 | 
| // }).then(Tasq.then).catch(Tasq.catch) | // }).then(Tasq.then).catch(Tasq.catch) | ||||
| // }) | // }) | ||||
| var bowerRepos = [{ repo : 'client'}] | |||||
| var bowerRepos = [{ repo : 'elixir-client'}]; | |||||
| var bowertasks = [] | var bowertasks = [] | ||||
| bowerRepos.forEach(repodef => { | bowerRepos.forEach(repodef => { | ||||
| bowertasks.push(() => { | bowertasks.push(() => { | 
| @echo off | |||||
| echo %PATH% | |||||
| set PATH=%PATH%;C:\Program Files\Git\cmd | |||||
| set PATH=%PATH%;C:\Program Files\nodejs\ | |||||
| set PATH=%PATH%;C:\Users\Pradeep\AppData\Local\Programs\Microsoft VS Code\bin | |||||
| set PATH=%PATH%;C:\Python27 | |||||
| SET LAUNCHEDWITHENV=YES && cscript D:\chess\elixir\dev\elxr\i.win.js /all:true | 
| "author": "", | "author": "", | ||||
| "license": "ISC", | "license": "ISC", | ||||
| "dependencies": { | "dependencies": { | ||||
| "bbhverse": "git+http://git.bbh.org.in/chess/bbhverse", | |||||
| "serververse": "git+http://git.bbh.org.in/chess/bbhverse", | |||||
| "bbhverse": "file:../bbhverse", | |||||
| "serververse": "file:../serververse", | |||||
| "chalk": "^4.1.0", | "chalk": "^4.1.0", | ||||
| "crossfilter2": "^1.5.4", | "crossfilter2": "^1.5.4", | ||||
| "glob": "^7.1.2", | "glob": "^7.1.2", | 
| #xrdp | #xrdp | ||||
| #----------------------- | #----------------------- | ||||
| sudo apt install xrdp | sudo apt install xrdp | ||||
| nano /etc/xrdp/startwm.sh | |||||
| sudo nano /etc/xrdp/startwm.sh | |||||
| Add in the very top: | Add in the very top: | ||||
| unset DBUS_SESSION_BUS_ADDRESS | unset DBUS_SESSION_BUS_ADDRESS | 
| var shell_verse = { | var shell_verse = { | ||||
| // getCommonTask is agnostic of whether we are running in an elevated shell or not. It runs in either case. | // getCommonTask is agnostic of whether we are running in an elevated shell or not. It runs in either case. | ||||
| init( o ){ Object.assign(this, o) } | init( o ){ Object.assign(this, o) } | ||||
| , downloadsdir : '../Downloads' | , downloadsdir : '../Downloads' | ||||
| , getCommonTask( taskToRun ){ return ()=>{ return shell_verse.runTask(taskToRun) }} | , getCommonTask( taskToRun ){ return ()=>{ return shell_verse.runTask(taskToRun) }} | ||||
| , runTask : ( taskToRun ) => { | , runTask : ( taskToRun ) => { | ||||
| , elevatedRunner( taskToRun, inBatch ){ | , elevatedRunner( taskToRun, inBatch ){ | ||||
| // PB : TODO -- Should be called only when we are in an elevated shell that was already requested from an unelevated shell with a batch of tasks. | // PB : TODO -- Should be called only when we are in an elevated shell that was already requested from an unelevated shell with a batch of tasks. | ||||
| try { | try { | ||||
| var runlogjson = `${selectedinstance.root}/.elxr/run-${taskToRun.runtimestamp}/run.log` | |||||
| var runlogjson = `${taskToRun.selectedinstance.root}/.elxr/run-${taskToRun.runtimestamp}/run.log` | |||||
| var __runasresult = null; | var __runasresult = null; | ||||
| return taskToRun().then((r)=>{ | return taskToRun().then((r)=>{ | ||||
| // PB : TODO -- Every elevation should have its own messaging file. Async writes from multiple processes are a problem here... | // PB : TODO -- Every elevation should have its own messaging file. Async writes from multiple processes are a problem here... | ||||
| , requestElevation(elevatedRunner, taskToRun) { | , requestElevation(elevatedRunner, taskToRun) { | ||||
| // PB : TODO -- Multiple parallel request elevations should be queued into a batch and serialized as a single promise. | // PB : TODO -- Multiple parallel request elevations should be queued into a batch and serialized as a single promise. | ||||
| var processedArgs = taskToRun.processedArgs, selectedinstance = taskToRun.selectedinstance , statuslog = taskToRun.statuslog | |||||
| var processedArgs = taskToRun.processedArgs, statuslog = taskToRun.statuslog | |||||
| // Wait for the runas to complete before we read it. | // Wait for the runas to complete before we read it. | ||||
| try { | try { | ||||
| fs.unlinkSync('run.done') // Need a unique file for aech elevated run. | fs.unlinkSync('run.done') // Need a unique file for aech elevated run. | ||||
| // Find node path to send to hta. | // Find node path to send to hta. | ||||
| return nodeShellExec('where', ['node']).then(r => { | 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 = [ path.normalize(`${selectedinstance.root}/.elxr/run-${taskToRun.runtimestamp}/windowselevate.hta`) ].concat(processedArgs._) | |||||
| namedArgs.length > 0 ? args = args.concat(namedArgs.join(' ')) : null; | |||||
| var args = taskToRun.args | |||||
| var options = taskToRun.args ? taskToRun.args.pop() : { | |||||
| inherit: true | |||||
| , shell: true | |||||
| , env: taskToRun.ENV | |||||
| , runas: 'self' | |||||
| , title: `runas` | |||||
| } | |||||
| options.env = Object.assign({}, taskToRun.ENV, { wd : options.cwd }) | |||||
| var spawntimestamp = (new Date()).getTime() | |||||
| if(!args) { | |||||
| 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. | |||||
| args = [].concat(processedArgs._) | |||||
| namedArgs.length > 0 ? args = args.concat(namedArgs.join(' ')) : null; | |||||
| } | |||||
| else { | |||||
| // args = args.splice(-1) -- Already popped | |||||
| args.push(`--root=${selectedinstance.root}`); | |||||
| } | |||||
| args.splice(0,0, path.normalize(`${taskToRun.selectedinstance.root}/.elxr/run-${taskToRun.runtimestamp}/windowselevate.hta`)) | |||||
| args.push('--runas=self'); | args.push('--runas=self'); | ||||
| var elevatedruntimestamp = (new Date()).getTime() | |||||
| args.push(`--runtimestamp=${elevatedruntimestamp}`); | |||||
| // args.debug = true | |||||
| if(args.debug) args.push(`--debug=${args.debug}`); | |||||
| args.push(`--runtimestamp=${spawntimestamp}`); | |||||
| // args.push(`--wd=${options.cwd}`); | |||||
| // args.push('--nodepath=' + r.messages[r.messages.length - 1]) | // args.push('--nodepath=' + r.messages[r.messages.length - 1]) | ||||
| // if (!processedArgs.node_env) args.push('--node_env=' + ENV.NODE_ENV) | // if (!processedArgs.node_env) args.push('--node_env=' + ENV.NODE_ENV) | ||||
| console.dir(args) | console.dir(args) | ||||
| // throw 'test' | // throw 'test' | ||||
| return nodeShellExec('MSHTA', [`"${args.join('" "')}"`] | |||||
| , { | |||||
| inherit: true | |||||
| , shell: true | |||||
| , env: taskToRun.ENV | |||||
| , runas: 'self' | |||||
| , title: `runas` | |||||
| } | |||||
| ).then(() => { | |||||
| return nodeShellExec('MSHTA', [`"${args.join('" "')}"`], options ).then(() => { | |||||
| // runas returned. | // runas returned. | ||||
| try { | try { | ||||
| // PB : TODO -- Log is comma prefixed. Needs to be proper JSON. | // PB : TODO -- Log is comma prefixed. Needs to be proper JSON. | ||||
| var runlogjson = `${selectedinstance.root}/.elxr/run-${elevatedruntimestamp}/run.log` | |||||
| var runlogjson = `${taskToRun.selectedinstance.root}/.elxr/run-${spawntimestamp}/run.log` | |||||
| var runaslog = JSON.parse('[' + fs.readFileSync(runlogjson, { flags: 'a+' }) + ']'); | var runaslog = JSON.parse('[' + fs.readFileSync(runlogjson, { flags: 'a+' }) + ']'); | ||||
| try { fs.unlinkSync(runlogjson) } catch(e){ } // PB : TODO -- Have a unique file for each elevated run. | try { fs.unlinkSync(runlogjson) } catch(e){ } // PB : TODO -- Have a unique file for each elevated run. | ||||
| // console.log( "runaslog : " + runaslog.length ) | // console.log( "runaslog : " + runaslog.length ) | ||||
| console.error('Run log error probably was not created by runas : ' + e) | console.error('Run log error probably was not created by runas : ' + e) | ||||
| } | } | ||||
| }) | }) | ||||
| .catch(err => console.error('Elevation failed : ' + err)); | |||||
| .catch(err => console.error('Elevation failed : ' + JSON.stringify(err))); | |||||
| }) | }) | ||||
| } | } | ||||
| , launchui() { | , launchui() { |