var scripthostName = 'node' var __Promise = {}; var promises = []; function startPromises(){ promises.forEach(function(p){ // console.log(p.chain) p ? p() : null; // promises.splice(0,1) }) } function isWin(){ return /^win/.test(process.platform) } var stampedFilePfx = function(date) { return date.getFullYear() + ('0' + (date.getMonth() + 1)).slice(-2) + ('0' + date.getDate()).slice(-2) + ('0' + date.getHours()).slice(-2) + ('0' + date.getMinutes()).slice(-2) + ('0' + date.getSeconds()).slice(-2); } var runtimestamp = (new Date()).getTime(); try { console.log("detected node") // var WScript = console || WScript // Dummy // console.Echo = console.log __Promise = Promise var __require = require var map = Array.map function startPromises(){ promises.forEach(function(p){ // console.log(p.chain) p ? Promise.resolve(p) === p ? p : p() : null; // promises.splice(0,1) }) } // -------------------------------------------- // Node Exists. Lets launch ourselves in Node itself WScript = function(){} WScript.Echo = function(m){ console.log('Invalid Wscript') throw "Failed in Node Run." } var wait = function(ms, cb) {any return new __Promise(function(resolve){ setTimeout(resolve, ms) } ).then(function(){ cb() }); } var fs = require('fs') var existsSync = require('fs').existsSync; var existsSyncFolder = existsSync var path = require('path'); console.log('before cliverse') var cli = require('./cliverse') var nodeShellExec = cli.nodeShellExec; console.log('before bbhverse') var utils = require('bbhverse'); var any = utils.any; var wait = setTimeout // -------------------------------------------- // PB : TODO -- This should be parent dir if elxr is already installed. var selectedinstance = { root : path.resolve(".") } __main(selectedinstance) } catch(e) { WScript.Echo('detected wsh') scripthostName = 'wsh' WScript.Echo(WScript.FullName) // WScript.Echo('--' + WScript.Arguments(0) + '--') // WScript.Echo('------------ALL-----------') // var argEnumerator = new Enumerator(WScript.Arguments) // for(; !argEnumerator.atEnd(); argEnumerator.moveNext()){ // WScript.Echo('-arg-' + argEnumerator.item() + '-arg-') // } // // Unnamed // WScript.Echo('------------UNNAMED-----------') // argEnumerator = new Enumerator(WScript.Arguments.Unnamed) // for(; !argEnumerator.atEnd(); argEnumerator.moveNext()){ // WScript.Echo('-arg-' + argEnumerator.item() + '-arg-') // Value // } // // Named // WScript.Echo('------------NAMED-----------') // argEnumerator = new Enumerator(WScript.Arguments.Named) // for(; !argEnumerator.atEnd(); argEnumerator.moveNext()){ // // WScript.Echo('-arg-' + argEnumerator.item(argEnumerator) + '-arg-') // Key // WScript.Echo('-key-' + argEnumerator.item() + '-key-') // Key // WScript.Echo('-val=' + WScript.Arguments.Named(argEnumerator.item()) + '=val-') // Value // } // cscript elxr/i.win.js /all:true var all = WScript.Arguments.Named('all'); trim = function(str) { return str.replace(/^\s+|\s+$/g, ''); }; var fs = new ActiveXObject('Scripting.FileSystemObject'); var WshShell = WScript.CreateObject("WScript.Shell") var ENV = WshShell.Environment("Process") var sfn = WScript.ScriptFullName // WScript.Echo(sfn) var cd = fs.GetAbsolutePathName(".") var cfn = cd + '\\i.win.js' // WScript.Echo(cfn) var waslaunchedwithenv = trim(ENV.Item('LAUNCHEDWITHENV')); // for(e=new Enumerator(ENV); !e.atEnd(); e.moveNext()) WScript.echo(e.item(e)); if(waslaunchedwithenv !== "YES"){ var a = fs.CreateTextFile("launchwithenv.bat", true) a.WriteLine("@echo off") a.WriteLine("echo %PATH%") var gitpath = "C:\\Program Files\\Git\\cmd" var nodepath = "C:\\Program Files\\nodejs\\" var codepath = "C:\\Users\\Pradeep\\AppData\\Local\\Programs\\Microsoft VS Code\\bin" a.WriteLine("set PATH=%PATH%;" + gitpath ) a.WriteLine("set PATH=%PATH%;" + nodepath ) a.WriteLine("set PATH=%PATH%;" + codepath ) // a.WriteLine("set LAUNCHEDWITHENV=YES" ) var __ALIAS__STAMP__ = '9e7bebe0-1f57-11ec-8f88-778ffeea9d1b' var currentIsExlr = function() { if(fs.FileExists('./' + __ALIAS__STAMP__)) return true } var runningInExlr = currentIsExlr() if(cfn === sfn && runningInExlr) { a.WriteLine("cd .."); a.WriteLine("SET LAUNCHEDWITHENV=YES && cscript "+cfn+" /all:true") // PB : TODO -- Retain all script args... } else { var guesselxr = fs.FileExists(cd + './elxr/' + __ALIAS__STAMP__) if(guesselxr) { a.WriteLine("SET LAUNCHEDWITHENV=YES && cscript "+cd + './elxr/' + 'i.win.js' +" /all:true") } else a.WriteLine("SET LAUNCHEDWITHENV=YES && cscript "+sfn+" /all:true") } // a.WriteLine("powershell.exe ^") // a.WriteLine("[Environment]::GetEnvironmentVariable('Path')" ) a.Close() WshShell.run("cmd /k launchwithenv.bat") WScript.Quit() // WshShell.run("powershell -noexit [Environment]::GetEnvironmentVariable(\"\"Path\"\"\) ") // WshShell.run("powershell -noexit [Environment]::SetEnvironmentVariable(\"\"Path\"\", $env:Path + \"\";C:\\tttt\"\", \"\"Machine\"\"\) ") } console = { log : function(m) { WScript.Echo(m)} , error : function(m) {WScript.Echo(m) } , dir : function(o) { for(var i in o){ console.log(i + ' : ' + o[i])} } } // if(!String.prototype.trim) String.prototype.trim = function(){ // return this.replace(/^\s+|\s+$/g, ''); // }; // var ovrrides = { // resolve : function(v){ // if(v && v.then) return v; // var p = new Promise(function(resolve, reject){ resolve(v) }); // return p; // } // }; // // -------------------------------------------- // // Cscript var wsh = true; function isWin(){ return true; } // If UCase( Right( WScript.FullName, 12 ) ) = "\CSCRIPT.EXE" Then var clii = { question : function(q, answercb){ WScript.Echo(q) // console.log('WScript.StdIn : ' + WScript.StdIn.ReadLine() + ' ==== ') var answer = WScript.StdIn.ReadLine() answercb(answer) } } var prompter = { ask : function(q){ // Needs to be serialized. Parallel asks are not possible. // const clii = readline.createInterface({ input: process.stdin, output: process.stdout }); return new Promise(function(resolve, reject){ clii.question(q, function(answer){ // clii.close(); // console.log("resolve is being called"); resolve(answer) }) }) } } var cli = { prompt : function(choices, label, defaultchoice){ var options = []; choices.forEach = forEach choices.forEach(function(choice){ options.push( ((+choice) + 1) + ' ' + choices[choice] )}) return prompter.ask( label + ' \\n ' + options.join('\n') + '\n default ( <= ' + (defaultchoice || choices[0]) + ' ) : ' ).then( function(choice){ if(!choice) return defaultchoice || choices[0]; if(choice && isNaN(+choice)) return choice; return choices[(+choice) - 1]; }) } } var any = function(iterable, continueOnFailure) { // var cancelsignal = Symbol() if(!iterable.reduce) iterable.reduce = reduce // console.log('iterable.reduce ' + iterable.reduce) var cancelsignal = "cancelme{mangledrunid}" return iterable.reduce( function(p, tasq, i ,a) { // console.dir(a) // console.log('Entered') var handleError = function(err, pVal){ if(err !== cancelsignal) { // Cancel only once on first failure. console.warn('Possible failure for task with result : ' ) console.log('Failed : ' + err.message + ' ') console.dir(pVal) console.dir(p) if(i>0 && a[i-1].info) console.dir(a[i-1].info) console.error('Error : ' + err.stack) console.error(a[i-1]) a[i-1] ? console.log("tasq : " + a[i-1].toString()) : null; if(!continueOnFailure) {console.log("Cancelling remaining on any one failure ..."); throw cancelsignal} else return pVal; // tasq ? console.log("tasq : " + tasq.toString()) : null; // Previous task is what failed not the one we are going to run. } } if(Promise.resolve(p) === p ) { if(i>0 && a[i-1].info) p.info = a[i-1].info; console.dir(' p.then is ' + p.then) return p.then( function(pVal){ // Falsy values are no longer treated as task failure exceptions. Specially for Promises. // Even tasq function wrappers are required to return promises that eventually either resolve or reject.. // Failures are known for promises on reject. // In future if we support direct sync function execution with a result examination for failure // we could examine the result of the function as falsy's... or a result evaluator handler needs to be passed in... // if(!pVal) handleError({ error : true, message : 'Failed without result' }, pVal) // Truthy values are failures if obj has error=true. if(pVal && pVal.error) handleError(pVal, pVal) var trycall = function(tasq){ try { var result = tasq() // PB : TODO -- Handle scope for call if(tasq.resultHandler) return tasq.resultHandler(result) // else (Promise.resolve(result) === result ) ? result.start() : null return result } catch (error) { console.error(error); console.error('Error : ' + error ? error.stack : 'No stack') if(!continueOnFailure) throw error; // PB : TODO -- Support array of results for any with or without continueonfailure. } } var handleNext = function(){ // console.log('Task finished with result : ') // console.dir(pVal) if(i>0 && a[i-1].info) console.dir(a[i-1].info) if(!tasq && !continueOnFailure) { console.log('Error : No task specified.'); throw false;} else if(!tasq) { console.log('Error : No task specified.'); return false;} return (Promise.resolve(tasq) === tasq ) ? tasq /*.start()*/ : trycall(tasq) ; } if(Promise.resolve(pVal) === pVal) { // Passed in function retured a promise. We still need to wait for it. pVal.then(function(pVal){ return handleNext(); }) } else return handleNext() })['catch'](function(error) { if(error !== cancelsignal) { console.log('E3 : i = ' + i); if(error.result) console.error(error.result) console.error('Error : ' + (error.message || error.messages)) console.error('Error : ' + error.stack) tasq ? console.log("tasq : " + tasq.toString()) : null; console.log('debugData 3-------------------------'); // handleError() throw error } else throw cancelsignal; }) } else if(!p) { handleError({ error : true, message : 'Failed without result' }, pVal) console.log("Bypass remaining on prior failure"); return false; // All remaining tasks will return false in the any results even if they are promisies still running or functions not initiated. } else return p; // A truthy value } , Promise.resolve(true) ); } // __Promise = ovrrides function forEach(eachFn){ for(var i=0; i -1) { return normalized.substring(0, li) } } , normalize : function(path){ return path.replace(/\//g,'\\'); } } // Detect or specify install directory. var selectedinstance = { root : path.resolve(".") } var existsSyncFolder = function(path){ return fso.FolderExists(path) } var shell = new ActiveXObject('shell.application'); promises.forEach = forEach function startPromises(){ promises.forEach(function(p){ // console.log(p.chain) p.start(); // promises.splice(0,1) }) } function batchshellescape(str) { return str.replace('=', '^=') } function nodeShellExec(command, cargs, options){ // for(var arg=0; arg < cargs.length; arg++) { // // cargs[arg] = '"' + batchshellescape(cargs[arg]) +'"'; // cargs[arg] = '"' + cargs[arg] +'"'; // } var elevatedshellexecute = function(cmd, argstr){ shell.ShellExecute(cmd, argstr , "", "", 1); } var shellExec = function(cmd, argstr){ var objShell = WScript.createobject("wscript.shell") // console.log(argstr.join( ' ')) console.log(cmd + ' ' + argstr.join(' ')) var oExec = objShell.Exec(cmd + ' ' + argstr.join(' ')) var result = {} var shellresult = { shell : objShell, result : result } var WshRunning = 0 var WshFinished = 1 var WshFailed = 2 while(oExec.Status === WshRunning){ WScript.StdOut.write('s.') WScript.Sleep(500) } var strOutput = '\n' switch(oExec.Status) { case WshFinished : strOutput = oExec.StdOut.ReadAll() result.success = true; result.code = 0 break; case WshFailed : strOutput = oExec.StdErr.ReadAll() result.success = false; result.code = WshFailed break; default : strOutput = 'failed' break; } result.result = command + ' ' + cargs + ' exited with code ' + result.code result.messages = [strOutput] // console.log(strOutput) // WScript.Echo(oExec.Status) // WScript.Echo(oExec.ProcessID) // WScript.Echo(oExec.ExitCode) // console.log(objShell.StdOut.ReadAll) // console.log(objShell.StdErr.ReadAll) // objShell = WScript.createobject("wscript.shell") objShell = null; return shellresult; } var p = null; var pworker = function(resolve, reject){ // console.dir(p) var pfx = selectedinstance.root + '\\.elxr\\run-' + runtimestamp + '\\' + stampedFilePfx(new Date()) // console.log('p.chain.length ================ ' + p.chain.length) options = options || { runFile : path.normalize( pfx + "out.txt") // runFile : null } var runFile = null; var runFile = options.runFile || pfx + command + cargs + "out.txt"; // console.log(runFile) var args = cargs.concat() // runFile ? (args.push(">"), args.push(runFile)) : cargs // console.log(command + ' ' + args.join(' ')) // command = 'cmd' // args = ['/c', 'start', // '/WAIT', selectedinstance.root + '/Downloads' + '/' + 'Git-2.33.0.2-64-bit.exe' // , '/VERYSILENT' // // , '/MERGETASKS=!runcode' // This is required only for vscode... // ] var runbat = path.normalize(pfx + "run.bat") // console.log('runbat : ' + runbat) fs.writeFileSync(runbat, '@echo off \r\n' + (options.cwd ? 'cd ' + options.cwd + ' \r\n' : '') + // ' cmd /k notepad.exe \r\n' + command + ' ' + args.join(' ') + ' \r\n' + 'cmd /c echo done >> ' + runFile + ' \r\n' + 'echo done' ) // fs.writeFileSync(runFile, 'started') // WScript.Quit() // elevatedshellexecute(runFile) // while(!existsSync(runbat)) { wait(function(){ // console.log('awiting batch : ' + runbat) // // shellExec( 'start', ['/W', '/b', runbat]) // // shellExec( 'cmd', ['/k', '/b', runbat]) // shellExec( command, args) // // cmd /b /c // }, 500) } console.log(options.waitmsg || ('awaiting ' + command + ' ' + args.join(' '))) var shellresult = shellExec( 'cmd', [ '/c', runbat]) // var shellresult = shellExec( 'cmd', ['/c', runbat]) // var shellresult = shellExec( command, args) var wrapup = function(result) { // console.log('Wrapping up') try { // console.log('resolving.....................'); // console.log('--------------P' + result.messages.join(' ').trim() +'P--------------') // if(result.messages.join().trim()) resolve(result) // else reject(result) resolve(result) } catch(e){ // console.dir(e) if(e.message === 'Input past end of file') { // console.log('---------------------------------------') // console.dir(result) resolve(result) } else { // console.dir(e) reject(e) } } } // if(runFile){ // var waitr = function(){ // WScript.StdOut.write('w.') // if(existsSync(runFile)) { // var strOutput = fs.readFileSync(runFile) // shellresult.result.messages = [strOutput] // wrapup(shellresult.result) // fs.unlinkSync(runFile) // } // // console.dir(shellresult.result) // wait( waitr, 500) // } // // console.log(wait) // wait( waitr, 500) // } // else { // console.log('There is no runfile.') console.log(shellresult.strOutput) wrapup(shellresult.result) // } } p = new Promise(pworker) // promises.push(p) // // Promise tThens don't get hooked up... we need to postpone promise starting until all the thens are registered... // wait(function(){ // console.log('p.chain.length' + p.chain.length) // p.start() } , 5000) // Bind and setTImeout is not supported by JScript return p; } createPromiseClass(/*ovrrides*/) __main( selectedinstance ) function createPromiseClass(overrides) { function reject(e){ var p = this; console.log('Promise Rejection : ' + p.fn) console.dir(e) // throw e;f if(p.state !== PromiseClass.PENDING) { console.error ('Error : Promise Rejection can only be called once')} var __i = 0; var __e = e; do { for(var i = __i; i < p.chain.length; i++, __i = i) if(p.chain[i].isCatch) break; try { for(var i = __i; i < p.chain.length; i++, __i = i) if(p.chain[i].isCatch) { p.chain[i](__e); break; } __i++; __e = null; } catch(e){ __i++; __e = e} } while(__e) do { try { for(var i = __i; i < p.chain.length; i++, __i = i) if(!p.chain[i].isCatch) { p.result = p.chain[i](p.result); } } catch(e){ __i ++; do { try { for(var i = __i; i < p.chain.length; i++, __i = i) if(p.chain[i].isCatch) { p.chain[i](__e); break; } __i ++; __e = null; } catch(e){ __i++; __e = e} } while(__e) } } while ( __i < p.chain.length ) p.state = PromiseClass.REJECTED; } function resolve(result){ var p = this; // console.log(result + ' resolve was called with chain length ' + p.chain.length ) if(p.state !== PromiseClass.PENDING) { console.error ('Error : Promise Resolve can only be called once')} p.result = result; if(PromiseClass.resolve(p.result) === p.result) { // console.log( 'result is still a promise waiting for result and promisechain' ) waitForResult(p.result, function(r){ p.processchain(r) }) } else { // console.log( 'result is value waiting for promisechain' ) // console.dir(result) return p.processchain(result) } }; function processchain(r){ var __i = 0; var i = __i; var __e = null; p = this; // console.log('processchain chain.length : ' + p.chain.length) function __processchain(r){ function waitForThen(p){ if(i < p.chain.length) { if(!p.chain[i].isCatch) { // console.log('chain idx : ' + i + ' Executing : then ' + p.result + ' ' + p.chain[i]) try { p.result = p.chain[i](p.result) if(PromiseClass.resolve(p.result) === p.result) { // console.log('chain idx : ' + i + ' result is still a promise starting it ') // console.dir(p.result.chain) // console.log('p.result.start : ' + p.result.start + ' ------------------ ') p.result.start() // console.log(p.result.fn + ' ------------------ ') waitForResult(p.result, function(r){ // console.log('we waited') // WScript.write('.') p.result = r; i++; __i = i; waitForThen(p) }) } else { i++; __i = i; waitForThen(p) } } catch(e) { i++; __i = i; __e = e; console.log('failed on index ' + __i + p.chain[__i-1] ) console.dir(e) waitForCatch(p); } } else { // console.log(i + ' Skipping catch : ' + p.result + ' ' + p.chain[i]) i++; __i = i; waitForThen(p) } } else return p.state = PromiseClass.FULFILLED; } function waitForCatch(p) { if(i < p.chain.length) { if(p.chain[i].isCatch) { console.log('chain idx : ' + i + ' Executing : catch : ' + p.result + ' ' + p.chain[i]) try { p.result = p.chain[i](__e); if(PromiseClass.resolve(p.result) === p.result) { p.result.start() waitForResult(p.result, function(r){ p.result = r; i++; __i = i; }) waitForThen(p) } else { p.result = r; i++; __i = i; waitForThen(p) } } catch(e){ i++; __i = i;; __e = e; waitForCatch(p) } } else { i++; __i = i; waitForCatch(p) } } else return p.state = PromiseClass.REJECTED } waitForThen(p); } __processchain(r) } var create = function(fn){ var p = { then : function(thenfn){ // console.log('Adding then') thenfn.isThen = true // if(Object.prototype.toString.call(p.chain) !== '[object Array]') console.dir(p.chain) p.chain.push(thenfn) return p; } , 'catch' : function(catchfn) { catchfn.isCatch = true p.chain.push(catchfn) return p; } , start : function(){ if(this.started) { console.error('Cannot start more than once...') return p }; this.started = true; this.fn = fn; try { fn( function(r){ // console.log('calling presolve in starter ') p.resolve(r) } , function(r){ p.reject(r) } ) } catch(e){ // console.log('start catch : ' + e) // console.log('p.chain.length : ' + p.chain.length) // // console.dir(p) // console.dir(e) // console.log(fn) p.reject(e) } return p } , state : PromiseClass.PENDING , chain : [] , reject : reject , resolve : resolve , processchain : processchain } p.chain.forEach = forEach; return p; } var PromiseClass = function(fn /*, donotstart */){ var p = create(fn) // if(!donotstart) { // wait(function(){ // console.log('p.chain.length' + p.chain.length) // p.start() } , 500) // Bind and setTImeout is not supported by JScript // } return p } PromiseClass.PENDING = 1 PromiseClass.FULFILLED = 2 PromiseClass.REJECTED = 3 // PromiseClass.STARTED = 4 PromiseClass.isSETTLED = function(p){ p.state === PromiseClass.FULFILLED || p.state === PromiseClass.REJECTED } PromiseClass.resolve = function(v){ if(v && v.then) return v; var p = create(function(resolve, reject){ resolve(v) }); // console.log('p.chain in resolve. length ' + p.chain.length) // p.result = v; // wait(function(){ p.processchain(v) }, 0) return p; } function waitForResult(p, cb){ if(!p) return cb(p) if(p.state !== PromiseClass.PENDING) cb(p.result) // console.log(p.state + ' Waiting for ..... ' + p.runFile) if(p.runFile && false) { while(!existsSync(p.runFile) && p.state === PromiseClass.PENDING) { console.log('Waiting for ResultFle'); wait(cb, 500) } cb(p.result) } else { // while(p.state === PromiseClass.PENDING) { // console.log('Waiting for Result') function waiter(){ // console.log(p.result) if(p.state === PromiseClass.PENDING) wait(waiter, 500); else return cb(p.result) } wait(waiter, 500) // } } } PromiseClass.all = any; // Serialized... PromiseClass.__all = function(arr){ arr.forEach = forEach; var resultPs = []; var results = []; console.log('All : ' + arr.length) var pAll = new PromiseClass(function(resolve, reject){ console.log('All started : ' + pAll) // console.dir(pAll) arr.forEach(function(p){ if(!p.then) { var pfn = p; p = new PromiseClass(function(resolve, reject){ try{ resolve(pfn()) } catch(e){ reject(e) } }) p.start() } else { // !p.start ? p.start = function(){return p} : null // p.start() // .then( function(){ waitForResult(p, function(r){ results.push(r) }) }) } resultPs.push(p) // waitForResult(p, function(r){ results.push(r) }) }) // PB : TODO -- This is the same as processchain!!! var allwaitr = function(){ var allResolved = true console.log('resultPs : ' + resultPs.length) for(var rIdx =0; rIdx < resultPs.length; rIdx++ ){ if(resultPs[rIdx]) { allResolved = false waitForResult(resultPs[rIdx], function(r){ if(Promise.resolve(r) !== r) results[rIdx] = r; resultPs[rIdx] = null; }) break; } } if(allResolved) { // console.log('All Reseloved') // console.dir(results) resolve(results) } else wait(allwaitr, 500) } wait(allwaitr, 500) }) // pAll.chain = arr; return pAll } // PromiseClass.resolve = overrides.resolve; Promise = PromiseClass; return PromiseClass; } } function __main( selectedinstance ){ var downloadsdir = selectedinstance.root + '/Downloads'; var callsheltask = function(args) { // console.log('callsheltask : ' + args) return function() { return nodeShellExec.apply(null, args) } } var gitUser = 'guest'; var gitEmail = 'guest@bbh.org.in'; var BUILD_VERSION = '[VI]Version: {version} - built on {date}[/VI]'; function getVersion() { return BUILD_VERSION; } console.log(getVersion()) function ensureDirectoryExistence(filePath) { var dirname = path.dirname(filePath); if (existsSyncFolder(dirname)) { return filePath; } ensureDirectoryExistence(dirname); fs.mkdirSync(dirname); return filePath; } var getTaskCheckExists = function(command, options) { options = options || {} return function() { var runFile = path.normalize(selectedinstance.root + '/.elxr/run-' + runtimestamp + '/' + stampedFilePfx(new Date()) + 'where' + command + "out.txt"); var p = nodeShellExec.apply(null, ['cmd', ['/c', 'where', command], { runFile : runFile } ]) p.runFile = runFile; if (options.ignorefailures) { return p.then(function(v) { // WScript.Echo('firstThen ' + v); return v })['catch']( function(e) { console.error(e); // Ignore. Not a major error if where command fails !!! throw e; }) } else return p.then(function() { // WScript.Echo('firstThen ddd'); return v }); } } function verifyAndInstallPrerequisites() { fs.writeFileSync(ensureDirectoryExistence(downloadsdir + '/readme.txt'), getVersion() + ' Your local downloads for this instance'); var downloadbatch = "::************************************************************************** \r\n \ :Download_ \r\n \ Powershell.exe ^\r\n \ $AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'; ^\r\n \ [System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols; ^\r\n \ (New-Object System.Net.WebClient).DownloadFile('%1','%2') \r\n \ exit /b \r\n \ ::**************************************************************************"; ensureDirectoryExistence(path.normalize(selectedinstance.root + '/.elxr/run-' + runtimestamp + '/readme.txt')) fs.writeFileSync(path.normalize(selectedinstance.root + '/.elxr/run-' + runtimestamp + '/download.bat'), downloadbatch); var downloadtasks = []; var installtasks = []; 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(exists) console.log(preq.shellcmd + ' is not installed'); 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 ) }); // console.log('downloadtasks') // console.dir(downloadtasks[0]) var p = Promise.all(downloadtasks).then(function(){ // console.log('calling install tasks : ' + installtasks.length) return any(installtasks) }) // console.log('Promise.all.chain : ' + p.chain) return p } // var choiceHandler = function(choices, choice) { // console.log('chosen : ' + choice) // var decision = choices['d']; // if (choice && choice === 'd' || !choice) { // decision = choices['d'] // } // else if (isNaN((+choice))) { // decision = choice // } // else decision = choices[choice-1] // if(!decision) throw 'Invalid selection : ' + decision // return decision // } // prereq definition helpers. We can't do proper inheritance in cscript. So fallback to global functions. function exists(next){ var self = this; console.log('checking existence of ' + self.shellcmd) return getTaskCheckExists(self.shellcmd, { ignorefailures: true })().then(function(exists) { // console.log('-------------exists=======================') // console.dir(exists) // console.log(exists + ' ' + self.shellcmd + ' exists') if(exists && exists.messages.join(' ').indexOf(self.shellcmd) > -1 ) { return true; } else return false })['catch'](function(e){ // console.log('-------------exists catch=======================') console.dir(e) return false; }) } function install() { var self = this; var ifns = [self.installcmd] if(!ifns.map) ifns.map = map; console.log('Installing') return any(ifns.map(callsheltask))['catch'](function(e){ if(e.code === 1602) { console.warn("Installation was probably cancelled.") } else throw e }).then(function(){ return self.postinstallsteps && self.postinstallsteps() }) } function unique(arr) { var hash = {}, result = []; for ( var i = 0, l = arr.length; i < l; ++i ) { if ( !hash.hasOwnProperty(arr[i]) ) { //it works with objects! in FF, at least hash[ arr[i] ] = true; result.push(arr[i]); } } return result; } // var ENV = Object.assign({}, process.env); // Shallow clone it. // WScript.echo( ENV("Path") ) function sysAddPathVar(path){ return true; // PB : TODO -- Not yet enabled. Remove sys path from path before saving. // Object.assign({ // inherit: true, shell: true, env: ENV, title: `${command} ${args}` // }, options) // var newpath = ENV("Path").split(';'); // newpath = Array.from(new Set(newpath.push(path))).join(';') var newpath = []; newpath.push(path) newpath = unique(newpath).join(';') // path.split(';').forEach(pel => { var kv = pel.split('='); kv[0] === key ? null : newpath.push(pel); } ) return any([nodeShellExec('setx', [/*'/m',*/ 'PATH', '"%PATH%;' + newpath + '"' ]) // , nodeShellExec('set', [/*'/m',*/ 'PATH', '"%PATH%;' + newpath + '"' ]) ] ); } var getCmdString = function(args){ return args[0] + ' ' + args[1].join(' ') } var getgitshelltask = function(args, onEachError) { return function(){ console.log('----------getgitshelltask--------------called') return nodeShellExec( "cmd", ['/c', getCmdString(args)], args[2]) // .catch( onEachError || function(e){ console.error(e) }) } } var prerequisites = [ { shellcmd: 'git', url: 'https://github.com/git-for-windows/git/releases/download/v2.33.0.windows.2/Git-2.33.0.2-64-bit.exe' , installer: 'Git-2.33.0.2-64-bit.exe' , installcmd: ['cmd', ['/c', 'start', '/WAIT', downloadsdir + '/' + 'Git-2.33.0.2-64-bit.exe' , '/VERYSILENT' // , '/MERGETASKS=!runcode' // This is required only for vscode... ]] , preinstallsteps: function() { var self = this; console.log('Git preinstall steps') var steps = []; // steps.push( // function(){ // // console.log('cli prompt steps') // var choices = { 0 : 'guest', 1 : 'chessdemo' } // return cli.prompt(choices, 'git user name', gitUser).then(function(choice){ gitUser = choice } ) // } // ) // steps.push( // function(){ // var choices = { 0 : 'guest@bbh.org.in', 1 : 'chessdemo@bbh.org.in' } // return cli.prompt(choices, 'git user email', gitEmail).then(function(choice){ gitEmail = choice }) // } // ) steps.push( function(){ if (!existsSync(downloadsdir + '/' + self.installer)) { return nodeShellExec(selectedinstance.root + '/.elxr/run-' + runtimestamp + '/download.bat', [self.url, downloadsdir + '/' + self.installer]) } else { console.log(self.installer + ' Already exits Download skipped.') return Promise.resolve(true) } } ) return any(steps) // return any([any(steps), any(prompts)]) } , installsteps: function () { var self = this; console.log('Git Installsteps called') var ifns = [self.installcmd] if(!ifns.map) ifns.map = map; return any(ifns.map(callsheltask))['catch'](function(e){ if(e.code === 1602) { console.warn("Installation was probably cancelled.") } else throw e }) } , postinstallsteps: function(){ // PB : TODO -- Detect failure or cancellation before attenpting postinstall steps... var steps = []; steps.push( function(){ var choices = { 0 : 'guest', 1 : 'chessdemo' } return cli.prompt(choices, 'git user name', gitUser).then(function(choice){ gitUser = choice } ) } ) steps.push( function(){ var choices = { 0 : 'guest@bbh.org.in', 1 : 'chessdemo@bbh.org.in' } return cli.prompt(choices, 'git user email', gitEmail).then(function(choice){ gitEmail = choice }) } ) return any(steps).then(function(){ var steps = [ ['git', ['config', '--global', '--add', 'user.name', gitUser]] , ['git', ['config', '--global', '--add', 'user.email', gitEmail]] ] if(!steps.map) steps.map = map; return any(steps.map(callsheltask)).then(function(){ }) }); } , install: function () { var self = this; console.log('Git Install called') var createTasq = function(args, shellT, onEachError) { var tasq = shellT ? shellT(args) : ( function(){ console.log('sdsfdsdf ' + args) return any([nodeShellExec.apply(null, args)]) // .catch( onEachError || function(e){ console.error(e) } ) }) tasq.toString = function(){ return JSON.stringify(args)} return tasq; } var execserial = function(tasklist, task, shellT, onEachError){ var exec = function(taskArgs){ console.log('execcing ' + task) var thistask = task.concat(); thistask[1] = thistask[1].concat() thistask[1].push.apply(thistask[1], taskArgs) return createTasq(thistask, shellT) } tasklist.map = map console.log('execlist ' + tasklist.map(exec)) return any(tasklist.map(exec)) } function resetgitconfig(){ // https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage // Git Credential storage... // git config --global credential.helper 'store --file ~/.gitcredentials' // git credential-store --file ~/.gitcredentials store // // notepad C:/Program Files/Git/etc/gitconfig // git config --global --unset credential // git config --edit --system // git config --global credential.helper "store --file ~/gitcredentials" // git credential fill // git credential-store --file ~/git.store store // Find system git config // git config --global --edit // git config --list --show-origin // git config --list --show-origin --show-scope // https://stackoverflow.com/questions/35942754/how-can-i-save-username-and-password-in-git // Recipie // git config --global --unset credentials.helper // cd /path/to/my/repo // git config --unset credential.helper // git config credential.helper 'store --file ~/.git_repo_credentials' // git config credential.*.username my_user_name // git config credential.https://gitlab.com.username my_user_name // git credential fill // git config --global credential.modalprompt false // doesnst work. // core askpass = ;;; https://stackoverflow.com/questions/37182847/how-do-i-disable-git-credential-manager-for-windows var options = { inherit: true, shell: true //, env: process.env , cwd: selectedinstance.root // , runas: processedArgs.runas } var task = ['git', ['config'], options] var tasklist = [ // ['--global', '--unset credentials.helper'] // ['--unset', 'credentials.helper'] // , // ['credential.helper', `'store --file git_repo_credentials'`] ['--global', 'credential.helper', "'store --file ~/.git_repo_credentials'"] , ['--global', '--replace-all', 'user.name', 'pb'] , ['--global', '--replace-all', 'user.email', 'pradeep@bbh.org.in'] // , ['--list'] // , ['credential', 'fill'] ] var onEachError = function(e) { console.error( e.messages.join('\n') + e.result + '\n' + util.inspect(e) + '\n') } var shellT = function(args) { return getgitshelltask(args, onEachError) // .catch(e => console.error( e.messages.join('\n') + e.result + '\n' + util.inspect(e) + '\n' + tasq.toString()) ) } execserial(tasklist, task, shellT, onEachError ) } return any([ /*self.preinstallsteps,*/ function(){ return self.installsteps() } , function() { resetgitconfig() } , function(){ return self.postinstallsteps() } ]) } , verifyAndInstall : function(){ var self = this; return self.exists().then( function(exits) { if(exists) return self.getUser(null, function(){ return self.postinstallsteps() } ) else return self.install(); }) } , exists : exists , getUser : function(repo, onNoResult){ onNoResult = onNoResult || function(){return false} var globalOrLocal = '--global'; if(!repo) globalOrLocal = '--global'; else globalOrLocal = '--local' var fns = [['git', ['config', globalOrLocal, '--get-all', 'user.name']]] if(!ifns.map) ifns.map = map; return any(fns.map(callsheltask)).then(function(result){ // not yet configured. if(!result.success) return onNoResult() else { var users = result.messages[0].trim().split('\n'); if(users.length === 0 || users.length === 1 && users[0] === 'guest') { return onNoResult() } else return users[0]; // PB : TODO == We should probably prompt with all the users available for selection ! } }) ['catch'](function(e){ console.log(e) return onNoResult() }) } } , { shellcmd: 'node', url: 'https://nodejs.org/dist/v14.17.6/node-v14.17.6-x64.msi' , installer: 'node-v14.17.3-x64.msi' , installcmd: ['MSIEXEC.exe', ['/i' , path.normalize(downloadsdir + '/' + 'node-v14.17.3-x64.msi') , 'ACCEPT=YES', '/passive']] , install : install , exists : exists , preinstallsteps: function() { var self = this; console.log('Node preinstall steps') 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' , optional : true , url: 'https://www.python.org/ftp/python/2.7.18/python-2.7.18.amd64.msi' , installer: 'python-2.7.18.amd64.msi' , installcmd: ['MSIEXEC.exe', ['/i' , path.normalize(downloadsdir + '/' + 'python-2.7.18.amd64.msi') , 'ACCEPT=YES', '/passive']] , preinstallsteps: function() { var self = this; console.log(self.shellcmd + ' preinstall steps') 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)]) } , install : install , postinstallsteps : function() { return sysAddPathVar('%USERPROFILE%\\AppData/Local\\Microsoft\\WindowsApps') } , exists : exists } , { shellcmd: 'code' , optional : true , url: 'https://code.visualstudio.com/sha/download?build=stable&os=win32-x64-user' , installer: 'VSCodeUserSetup-x64-1.65.2.exe' , installcmd: ['cmd /c', ['start /WAIT ' + downloadsdir + '/' + 'VSCodeUserSetup-x64-1.65.2.exe /VERYSILENT' // , '/MERGETASKS=!runcode' // This is required only for vscode... ]] , preinstallsteps: function() { var self = this; console.log(self.shellcmd + ' preinstall steps') var steps = []; steps.push( function(){ if (!existsSync(downloadsdir + '/' + self.installer)) { console.log(self.url) 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)]) } , install : install , postinstallsteps : function() { return sysAddPathVar('%USERPROFILE%\\AppData/Local\\Microsoft\\WindowsApps') } , exists : exists } , { shellcmd: 'sqlexpress', url: 'https://go.microsoft.com/fwlink/?linkid=866658' , installer: 'SQL2019-SSEI-Expr.exe' , installcmd: ['cmd', ['/c', 'start', '/WAIT', downloadsdir + '/' + 'SQL2019-SSEI-Expr.exe' , '/Quiet' //, 'SSMSInstallRoot=%systemdrive%\\Program Files (x86)\\Microsoft SQL Server\\140\\Tools\\Binn\\ManagementStudio' ]] , install : install , exists : exists , preinstallsteps: function() { var self = this; console.log('Node preinstall steps') 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: 'Ssms2019.exe', url: 'https://aka.ms/ssmsfullsetup' , installer: 'SSMS-Setup-ENU.exe' , installcmd: ['cmd', ['/c', 'start', '/WAIT', downloadsdir + '/' + 'SSMS-Setup-ENU.exe' , '/Quiet' //, 'SSMSInstallRoot=%systemdrive%\\Program Files (x86)\\Microsoft SQL Server\\140\\Tools\\Binn\\ManagementStudio' ]] , install : install , exists : exists , preinstallsteps: function() { var self = this; console.log('smss preinstall steps') var steps = []; steps.push( function(){ if (!existsSync(downloadsdir + '/' + self.installer)) { console.log(self.url) 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: 'Ssms.exe', url: 'https://go.microsoft.com/fwlink/?linkid=2043154&clcid=0x409' , installer: 'SSMS-Setup-ENU.exe' , installcmd: ['cmd', ['/c', 'start', '/WAIT', downloadsdir + '/' + 'SSMS-Setup-ENU.exe' , '/Quiet' //, 'SSMSInstallRoot=%systemdrive%\\Program Files (x86)\\Microsoft SQL Server\\140\\Tools\\Binn\\ManagementStudio' ]] , install : install , exists : exists , preinstallsteps: function() { var self = this; console.log('smss preinstall steps') var steps = []; steps.push( function(){ if (!existsSync(downloadsdir + '/' + self.installer)) { console.log(self.url) 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: 'mysql', url: 'https://dev.mysql.com/get/Downloads/MySQLInstaller/mysql-installer-community-8.0.30.0.msi' //'https://dev.mysql.com/get/Downloads/MySQLInstaller/mysql-installer-community-8.0.29.0.msi' , installer: 'mysql-installer-community-8.0.30.0.msi' , installcmd: ['MSIEXEC.exe', ['/i' , path.normalize(downloadsdir + '/' + 'mysql-installer-community-8.0.30.0.msi') //, 'ACCEPT=YES', '/passive' ]] , install : install , exists : exists , preinstallsteps: function() { var self = this; console.log('mysql preinstall steps') var steps = []; steps.push( function(){ if (!existsSync(downloadsdir + '/' + self.installer)) { console.log(self.url) 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: 'elxr' , forceinstall : true , installcmd: [ isWin() ? 'npm.cmd' : 'npm' , ['link'], { cwd : selectedinstance.root + '\\elxr' /* cwd should be the cloned dir*/}] , preinstallsteps: function() { var self = this; console.log('Elxr preinstall steps') var steps = []; steps.push( ) return any([any(steps)]) } , installsteps: function () { var self = this; console.log('Elxr Installsteps called') var installIfNotExists = function(){ console.log('Elxr PreInstallsteps called') var steps = []; var chessRepo = 'https://git.bbh.org.in' steps.push( function(){ // console.log('cli prompt steps') var choices = { 0 : 'http://git.bbh', 1 : 'https://git.bbh.org.in' } return cli.prompt(choices, 'git repository : ', chessRepo).then(function(choice){ chessRepo = choice } ) } ) return any(steps).then(function(chessRepo){ var ifns = [ ['git', ['clone', chessRepo + '/chess/elxr'] ] ] if(existsSyncFolder( selectedinstance.root + '\\elxr')) { if(existsSyncFolder( selectedinstance.root + '\\elxr\\.git')) { // PB : TODO -- use a elxr guid signature to detect more reliably folders named the same that is not us. ifns = [ ['git', ['pull'], { cwd : selectedinstance.root + '\\elxr' } ] ] } else { throw 'elxr subfolder not recognized as a git repository. Please cleanup and continue.' } } else console.log(selectedinstance.root + '\\elxr' + ' NOT FOUND ') ifns.push(['npm', ['i'], { cwd : '.\\elxr' } ]) if(!ifns.map) ifns.map = map; return any(ifns.map(callsheltask))['catch'](function(e){ if(e.code === 1602) { console.warn("Installation was probably cancelled.") } else throw e }) }) } var ifns = [ self.installcmd ] if(!ifns.map) ifns.map = map; return installIfNotExists().then(function(){ return any(ifns.map(callsheltask))['catch'](function(e){ if(e.code === 1602) { console.warn("Installation was probably cancelled.") } else throw e }) }) } , install: function () { var self = this; console.log('Elxr Install called') return any([ self.preinstallsteps, function(){ return self.installsteps() } , nodeShellExec('start', ['""', '"C:\\Program Files\\Git\\bin\\sh.exe"', '-c', '"node ' + (selectedinstance.root + '\\elxr\\index.js').replace(/\\/g, '/') + ' i elixir"']) // , nodeShellExec('node', [selectedinstance.root + 'elxr\\index.js']) ]) } // , exists : function(){ // console.log('Elxr PreInstallsteps called') // var ifns = [ ['git', ['clone', 'http://git.bbh/chess\\elxr'] ] ] // if(existsSyncFolder( selectedinstance.root + '\\elxr')) { // if(existsSyncFolder( selectedinstance.root + '\\elxr\\.git')) { // // PB : TODO -- use a elxr guid signature to detect more reliably folders named the same that is not us. // ifns = [ ['git', ['pull'], { cwd : selectedinstance.root + '\\elxr' } ] ] // } // else { // throw 'elxr subfolder not recognized as a git repository. Please cleanup and continue.' // } // } // else console.log(selectedinstance.root + '\\elxr' + ' NOT FOUND ') // if(!ifns.map) ifns.map = map; // return any(ifns.map(callsheltask))['catch'](function(e){ // if(e.code === 1602) { // console.warn("Installation was probably cancelled.") // } // else throw e // }) // } , exists : exists } ] if(!prerequisites.forEach) prerequisites.forEach = forEach; // nodeShellExec(selectedinstance.root + '/.elxr/run-' + '1629889572461' + '/download.bat' // , ['https://github.com/git-for-windows/git/releases/download/v2.31.0.windows.1/Git-2.32.0.2-64-bit.exe' // , downloadsdir + '/' + 'Git-2.32.0.2-64-bit.exe']).start() promises.push(verifyAndInstallPrerequisites()) startPromises(); }