555
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246
  1. var scripthostName = 'node'
  2. var __Promise = {};
  3. var promises = [];
  4. function startPromises(){
  5. promises.forEach(function(p){
  6. // console.log(p.chain)
  7. p ? p() : null;
  8. // promises.splice(0,1)
  9. })
  10. }
  11. function isWin(){ return /^win/.test(process.platform) }
  12. var stampedFilePfx = function(date) {
  13. return date.getFullYear() +
  14. ('0' + (date.getMonth() + 1)).slice(-2) +
  15. ('0' + date.getDate()).slice(-2) +
  16. ('0' + date.getHours()).slice(-2) +
  17. ('0' + date.getMinutes()).slice(-2) +
  18. ('0' + date.getSeconds()).slice(-2);
  19. }
  20. var runtimestamp = (new Date()).getTime();
  21. try {
  22. console.log("detected node")
  23. // var WScript = console || WScript // Dummy
  24. // console.Echo = console.log
  25. __Promise = Promise
  26. var __require = require
  27. var map = Array.map
  28. function startPromises(){
  29. promises.forEach(function(p){
  30. // console.log(p.chain)
  31. p ? Promise.resolve(p) === p ? p : p() : null;
  32. // promises.splice(0,1)
  33. })
  34. }
  35. // --------------------------------------------
  36. // Node Exists. Lets launch ourselves in Node itself
  37. var wait = function(ms, cb) {any
  38. return new __Promise(function(resolve){ setTimeout(resolve, ms) } ).then(function(){ cb() });
  39. }
  40. var fs = require('fs')
  41. var existsSync = require('fs').existsSync;
  42. var existsSyncFolder = existsSync
  43. var path = require('path');
  44. var cli = require('./cliverse')
  45. var nodeShellExec = cli.nodeShellExec;
  46. var utils = require('bbhverse');
  47. var any = utils.any;
  48. var wait = setTimeout
  49. // --------------------------------------------
  50. var selectedinstance = { root : path.resolve(".") }
  51. __main(selectedinstance)
  52. }
  53. catch(e) {
  54. WScript.Echo('detected wsh')
  55. scripthostName = 'wsh'
  56. WScript.Echo(WScript.FullName)
  57. // WScript.Echo('--' + WScript.Arguments(0) + '--')
  58. // WScript.Echo('------------ALL-----------')
  59. // var argEnumerator = new Enumerator(WScript.Arguments)
  60. // for(; !argEnumerator.atEnd(); argEnumerator.moveNext()){
  61. // WScript.Echo('-arg-' + argEnumerator.item() + '-arg-')
  62. // }
  63. // // Unnamed
  64. // WScript.Echo('------------UNNAMED-----------')
  65. // argEnumerator = new Enumerator(WScript.Arguments.Unnamed)
  66. // for(; !argEnumerator.atEnd(); argEnumerator.moveNext()){
  67. // WScript.Echo('-arg-' + argEnumerator.item() + '-arg-') // Value
  68. // }
  69. // // Named
  70. // WScript.Echo('------------NAMED-----------')
  71. // argEnumerator = new Enumerator(WScript.Arguments.Named)
  72. // for(; !argEnumerator.atEnd(); argEnumerator.moveNext()){
  73. // // WScript.Echo('-arg-' + argEnumerator.item(argEnumerator) + '-arg-') // Key
  74. // WScript.Echo('-key-' + argEnumerator.item() + '-key-') // Key
  75. // WScript.Echo('-val=' + WScript.Arguments.Named(argEnumerator.item()) + '=val-') // Value
  76. // }
  77. var all = WScript.Arguments.Named('all');
  78. console = {
  79. log : function(m) { WScript.Echo(m)}
  80. , error : function(m) {WScript.Echo(m) }
  81. , dir : function(o) {
  82. for(var i in o){ console.log(i + ' : ' + o[i])}
  83. }
  84. }
  85. // if(!String.prototype.trim) String.prototype.trim = function(){
  86. // return this.replace(/^\s+|\s+$/g, '');
  87. // };
  88. // var ovrrides = {
  89. // resolve : function(v){
  90. // if(v && v.then) return v;
  91. // var p = new Promise(function(resolve, reject){ resolve(v) });
  92. // return p;
  93. // }
  94. // };
  95. // // --------------------------------------------
  96. // // Cscript
  97. var wsh = true;
  98. function isWin(){ return true; }
  99. // If UCase( Right( WScript.FullName, 12 ) ) = "\CSCRIPT.EXE" Then
  100. var clii = {
  101. question : function(q, answercb){
  102. WScript.Echo(q)
  103. // console.log('WScript.StdIn : ' + WScript.StdIn.ReadLine() + ' ==== ')
  104. var answer = WScript.StdIn.ReadLine()
  105. answercb(answer)
  106. }
  107. }
  108. var prompter = {
  109. ask : function(q){
  110. // Needs to be serialized. Parallel asks are not possible.
  111. // const clii = readline.createInterface({ input: process.stdin, output: process.stdout });
  112. return new Promise(function(resolve, reject){
  113. clii.question(q, function(answer){
  114. // clii.close();
  115. // console.log("resolve is being called");
  116. resolve(answer)
  117. })
  118. })
  119. }
  120. }
  121. var cli = {
  122. prompt : function(choices, label, defaultchoice){
  123. var options = [];
  124. choices.forEach = forEach
  125. choices.forEach(function(choice){ options.push( ((+choice) + 1) + ' ' + choices[choice] )})
  126. return prompter.ask( label + ' \\n ' + options.join('\n') + '\n default ( <= ' + (defaultchoice || choices[0]) + ' ) : '
  127. ).then( function(choice){
  128. if(!choice) return defaultchoice || choices[0];
  129. if(choice && isNaN(+choice)) return choice;
  130. return choices[(+choice) - 1];
  131. })
  132. }
  133. }
  134. var any = function(iterable, continueOnFailure) {
  135. // var cancelsignal = Symbol()
  136. if(!iterable.reduce) iterable.reduce = reduce
  137. // console.log('iterable.reduce ' + iterable.reduce)
  138. var cancelsignal = "cancelme{mangledrunid}"
  139. return iterable.reduce(
  140. function(p, tasq, i ,a) {
  141. // console.dir(a)
  142. // console.log('Entered')
  143. var handleError = function(err, pVal){
  144. if(err !== cancelsignal) {
  145. // Cancel only once on first failure.
  146. console.warn('Possible failure for task with result : ' )
  147. console.log('Failed : ' + err.message + ' ')
  148. console.dir(pVal)
  149. console.dir(p)
  150. if(i>0 && a[i-1].info) console.dir(a[i-1].info)
  151. console.error('Error : ' + err.stack)
  152. console.error(a[i-1])
  153. a[i-1] ? console.log("tasq : " + a[i-1].toString()) : null;
  154. if(!continueOnFailure) {console.log("Cancelling remaining on any one failure ..."); throw cancelsignal}
  155. else return pVal;
  156. // tasq ? console.log("tasq : " + tasq.toString()) : null; // Previous task is what failed not the one we are going to run.
  157. }
  158. }
  159. if(Promise.resolve(p) === p ) {
  160. if(i>0 && a[i-1].info) p.info = a[i-1].info;
  161. console.dir(' p.then is ' + p.then)
  162. return p.then( function(pVal){
  163. // Falsy values are no longer treated as task failure exceptions. Specially for Promises.
  164. // Even tasq function wrappers are required to return promises that eventually either resolve or reject..
  165. // Failures are known for promises on reject.
  166. // In future if we support direct sync function execution with a result examination for failure
  167. // we could examine the result of the function as falsy's... or a result evaluator handler needs to be passed in...
  168. // if(!pVal) handleError({ error : true, message : 'Failed without result' }, pVal)
  169. // Truthy values are failures if obj has error=true.
  170. if(pVal && pVal.error) handleError(pVal, pVal)
  171. var trycall = function(tasq){
  172. try {
  173. var result = tasq() // PB : TODO -- Handle scope for call
  174. if(tasq.resultHandler) return tasq.resultHandler(result)
  175. // else (Promise.resolve(result) === result ) ? result.start() : null
  176. return result
  177. } catch (error) {
  178. console.error(error);
  179. console.error('Error : ' + error ? error.stack : 'No stack')
  180. if(!continueOnFailure) throw error; // PB : TODO -- Support array of results for any with or without continueonfailure.
  181. }
  182. }
  183. var handleNext = function(){
  184. // console.log('Task finished with result : ')
  185. // console.dir(pVal)
  186. if(i>0 && a[i-1].info) console.dir(a[i-1].info)
  187. if(!tasq && !continueOnFailure) { console.log('Error : No task specified.'); throw false;}
  188. else if(!tasq) { console.log('Error : No task specified.'); return false;}
  189. return (Promise.resolve(tasq) === tasq ) ? tasq /*.start()*/ : trycall(tasq) ;
  190. }
  191. if(Promise.resolve(pVal) === pVal) {
  192. // Passed in function retured a promise. We still need to wait for it.
  193. pVal.then(function(pVal){ return handleNext(); })
  194. }
  195. else return handleNext()
  196. })['catch'](function(error) {
  197. if(error !== cancelsignal) {
  198. console.log('E3 : i = ' + i);
  199. if(error.result) console.error(error.result)
  200. console.error('Error : ' + (error.message || error.messages))
  201. console.error('Error : ' + error.stack)
  202. tasq ? console.log("tasq : " + tasq.toString()) : null;
  203. console.log('debugData 3-------------------------');
  204. // handleError()
  205. throw error
  206. }
  207. else throw cancelsignal;
  208. })
  209. }
  210. else if(!p) {
  211. handleError({ error : true, message : 'Failed without result' }, pVal)
  212. console.log("Bypass remaining on prior failure");
  213. return false; // All remaining tasks will return false in the any results even if they are promisies still running or functions not initiated.
  214. }
  215. else return p; // A truthy value
  216. }
  217. , Promise.resolve(true)
  218. );
  219. }
  220. // __Promise = ovrrides
  221. function forEach(eachFn){
  222. for(var i=0; i<this.length; i++) eachFn(this[i])
  223. }
  224. function reduce(reducnFn, iv){
  225. var acc = iv
  226. for(var i=0; i<this.length; i++) {acc = reducnFn(acc, this[i], i, this) }
  227. return acc;
  228. }
  229. function map(eachFn){
  230. var mapped = []
  231. for(var i=0; i<this.length; i++) mapped.push(eachFn(this[i]))
  232. return mapped
  233. }
  234. var wait = function(cb, ms) { WScript.Sleep(ms); cb() }
  235. var fso = new ActiveXObject('Scripting.FileSystemObject');
  236. var existsSync = function(filepath){ return fso.FileExists(filepath) }
  237. var fs = {
  238. writeFileSync : function(filepath, text) {
  239. // console.log(filepath)
  240. var fh = fso.CreateTextFile(filepath, true);
  241. fh.WriteLine(text);
  242. fh.Close();
  243. }
  244. , mkdirSync : function(path) {
  245. fso.CreateFolder(path)
  246. }
  247. , readFileSync : function(filepath){
  248. var objFileToRead = fso.OpenTextFile(filepath,1)
  249. var strFileText = objFileToRead.ReadAll()
  250. objFileToRead.Close()
  251. return strFileText
  252. }
  253. , unlinkSync : function(filepath){ fso.DeleteFile(filepath) }
  254. }
  255. var path = {
  256. resolve : function(path){ return fso.GetAbsolutePathName(path) }
  257. , dirname : function(filepath) {
  258. var normalized = this.normalize(filepath)
  259. var li = normalized.lastIndexOf("\\")
  260. if( li > -1) {
  261. return normalized.substring(0, li)
  262. }
  263. }
  264. , normalize : function(path){
  265. return path.replace(/\//g,'\\');
  266. }
  267. }
  268. // Detect or specify install directory.
  269. var selectedinstance = { root : path.resolve(".") }
  270. var existsSyncFolder = function(path){
  271. return fso.FolderExists(path)
  272. }
  273. var shell = new ActiveXObject('shell.application');
  274. promises.forEach = forEach
  275. function startPromises(){
  276. promises.forEach(function(p){
  277. // console.log(p.chain)
  278. p.start();
  279. // promises.splice(0,1)
  280. })
  281. }
  282. function nodeShellExec(command, cargs, options){
  283. var elevatedshellexecute = function(cmd, argstr){
  284. shell.ShellExecute(cmd, argstr , "", "", 1);
  285. }
  286. var shellExec = function(cmd, argstr){
  287. var objShell = WScript.createobject("wscript.shell")
  288. // console.log(argstr.join( ' '))
  289. var oExec = objShell.Exec(cmd + ' ' + argstr.join(' '))
  290. var result = {}
  291. var shellresult = { shell : objShell, result : result }
  292. var WshRunning = 0
  293. var WshFinished = 1
  294. var WshFailed = 2
  295. while(oExec.Status === WshRunning){
  296. WScript.StdOut.write('s.')
  297. WScript.Sleep(500)
  298. }
  299. var strOutput = '\n'
  300. switch(oExec.Status) {
  301. case WshFinished :
  302. strOutput = oExec.StdOut.ReadAll()
  303. result.success = true;
  304. result.code = 0
  305. break;
  306. case WshFailed :
  307. strOutput = oExec.StdErr.ReadAll()
  308. result.success = false;
  309. result.code = WshFailed
  310. break;
  311. default : strOutput = 'failed'
  312. break;
  313. }
  314. result.result = command + ' ' + cargs + ' exited with code ' + result.code
  315. result.messages = [strOutput]
  316. // console.log(strOutput)
  317. // WScript.Echo(oExec.Status)
  318. // WScript.Echo(oExec.ProcessID)
  319. // WScript.Echo(oExec.ExitCode)
  320. // console.log(objShell.StdOut.ReadAll)
  321. // console.log(objShell.StdErr.ReadAll)
  322. // objShell = WScript.createobject("wscript.shell")
  323. objShell = null;
  324. return shellresult;
  325. }
  326. var p = null;
  327. var pworker = function(resolve, reject){
  328. // console.dir(p)
  329. var pfx = selectedinstance.root + '\\.elxr\\run-' + runtimestamp + '\\' + stampedFilePfx(new Date())
  330. // console.log('p.chain.length ================ ' + p.chain.length)
  331. options = options || {
  332. runFile : path.normalize( pfx + "out.txt")
  333. // runFile : null
  334. }
  335. var runFile = null;
  336. var runFile = options.runFile || pfx + command + cargs + "out.txt";
  337. // console.log(runFile)
  338. var args = cargs.concat()
  339. // runFile ? (args.push(">"), args.push(runFile)) : cargs
  340. // console.log(command + ' ' + args.join(' '))
  341. // command = 'cmd'
  342. // args = ['/c', 'start',
  343. // '/WAIT', selectedinstance.root + '/Downloads' + '/' + 'Git-2.33.0.2-64-bit.exe'
  344. // , '/VERYSILENT'
  345. // // , '/MERGETASKS=!runcode' // This is required only for vscode...
  346. // ]
  347. var runbat = path.normalize(pfx + "run.bat")
  348. // console.log('runbat : ' + runbat)
  349. fs.writeFileSync(runbat,
  350. '@echo off \r\n' +
  351. (options.cwd ? 'cd ' + options.cwd + ' \r\n' : '') +
  352. // ' cmd /k notepad.exe \r\n' +
  353. command + ' ' + args.join(' ') + ' \r\n' +
  354. 'cmd /c echo done >> ' + runFile + ' \r\n' +
  355. 'echo done'
  356. )
  357. // fs.writeFileSync(runFile, 'started')
  358. // WScript.Quit()
  359. // elevatedshellexecute(runFile)
  360. // while(!existsSync(runbat)) { wait(function(){
  361. // console.log('awiting batch : ' + runbat)
  362. // // shellExec( 'start', ['/W', '/b', runbat])
  363. // // shellExec( 'cmd', ['/k', '/b', runbat])
  364. // shellExec( command, args)
  365. // // cmd /b /c
  366. // }, 500) }
  367. console.log(options.waitmsg || ('awaiting ' + command + ' ' + args.join(' ')))
  368. var shellresult = shellExec( 'cmd', [ '/c', runbat])
  369. // var shellresult = shellExec( 'cmd', ['/c', runbat])
  370. // var shellresult = shellExec( command, args)
  371. var wrapup = function(result) {
  372. // console.log('Wrapping up')
  373. try {
  374. // console.log('resolving.....................');
  375. // console.log('--------------P' + result.messages.join(' ').trim() +'P--------------')
  376. // if(result.messages.join().trim()) resolve(result)
  377. // else reject(result)
  378. resolve(result)
  379. }
  380. catch(e){
  381. // console.dir(e)
  382. if(e.message === 'Input past end of file') {
  383. // console.log('---------------------------------------')
  384. // console.dir(result)
  385. resolve(result)
  386. }
  387. else {
  388. // console.dir(e)
  389. reject(e)
  390. }
  391. }
  392. }
  393. // if(runFile){
  394. // var waitr = function(){
  395. // WScript.StdOut.write('w.')
  396. // if(existsSync(runFile)) {
  397. // var strOutput = fs.readFileSync(runFile)
  398. // shellresult.result.messages = [strOutput]
  399. // wrapup(shellresult.result)
  400. // fs.unlinkSync(runFile)
  401. // }
  402. // // console.dir(shellresult.result)
  403. // wait( waitr, 500)
  404. // }
  405. // // console.log(wait)
  406. // wait( waitr, 500)
  407. // }
  408. // else {
  409. // console.log('There is no runfile.')
  410. // console.log(shellresult.strOutput)
  411. wrapup(shellresult.result)
  412. // }
  413. }
  414. p = new Promise(pworker)
  415. // promises.push(p)
  416. // // Promise tThens don't get hooked up... we need to postpone promise starting until all the thens are registered...
  417. // wait(function(){
  418. // console.log('p.chain.length' + p.chain.length)
  419. // p.start() } , 5000) // Bind and setTImeout is not supported by JScript
  420. return p;
  421. }
  422. createPromiseClass(/*ovrrides*/)
  423. __main( selectedinstance )
  424. function createPromiseClass(overrides) {
  425. function reject(e){
  426. var p = this;
  427. console.log('Promise Rejection : ' + p.fn)
  428. console.dir(e)
  429. // throw e;f
  430. if(p.state !== PromiseClass.PENDING) { console.error ('Error : Promise Rejection can only be called once')}
  431. var __i = 0;
  432. var __e = e;
  433. do {
  434. for(var i = __i; i < p.chain.length; i++, __i = i) if(p.chain[i].isCatch) break;
  435. try {
  436. for(var i = __i; i < p.chain.length; i++, __i = i) if(p.chain[i].isCatch) { p.chain[i](__e); break; }
  437. __i++;
  438. __e = null;
  439. }
  440. catch(e){ __i++; __e = e}
  441. } while(__e)
  442. do {
  443. try { for(var i = __i; i < p.chain.length; i++, __i = i) if(!p.chain[i].isCatch) { p.result = p.chain[i](p.result); } }
  444. catch(e){
  445. __i ++;
  446. do {
  447. try {
  448. for(var i = __i; i < p.chain.length; i++, __i = i) if(p.chain[i].isCatch) { p.chain[i](__e); break; }
  449. __i ++;
  450. __e = null;
  451. }
  452. catch(e){ __i++; __e = e}
  453. } while(__e)
  454. }
  455. } while ( __i < p.chain.length )
  456. p.state = PromiseClass.REJECTED;
  457. }
  458. function resolve(result){
  459. var p = this;
  460. // console.log(result + ' resolve was called with chain length ' + p.chain.length )
  461. if(p.state !== PromiseClass.PENDING) { console.error ('Error : Promise Resolve can only be called once')}
  462. p.result = result;
  463. if(PromiseClass.resolve(p.result) === p.result) {
  464. // console.log( 'result is still a promise waiting for result and promisechain' )
  465. waitForResult(p.result, function(r){ p.processchain(r) })
  466. }
  467. else {
  468. // console.log( 'result is value waiting for promisechain' )
  469. // console.dir(result)
  470. return p.processchain(result)
  471. }
  472. };
  473. function processchain(r){
  474. var __i = 0;
  475. var i = __i;
  476. var __e = null;
  477. p = this;
  478. // console.log('processchain chain.length : ' + p.chain.length)
  479. function __processchain(r){
  480. function waitForThen(p){
  481. if(i < p.chain.length) {
  482. if(!p.chain[i].isCatch) {
  483. // console.log('chain idx : ' + i + ' Executing : then ' + p.result + ' ' + p.chain[i])
  484. try {
  485. p.result = p.chain[i](p.result)
  486. if(PromiseClass.resolve(p.result) === p.result) {
  487. // console.log('chain idx : ' + i + ' result is still a promise starting it ')
  488. // console.dir(p.result.chain)
  489. // console.log('p.result.start : ' + p.result.start + ' ------------------ ')
  490. p.result.start()
  491. // console.log(p.result.fn + ' ------------------ ')
  492. waitForResult(p.result, function(r){
  493. // console.log('we waited')
  494. // WScript.write('.')
  495. p.result = r; i++; __i = i;
  496. waitForThen(p)
  497. })
  498. }
  499. else {
  500. i++; __i = i;
  501. waitForThen(p)
  502. }
  503. }
  504. catch(e) {
  505. i++; __i = i;
  506. __e = e;
  507. console.log('failed on index ' + __i + p.chain[__i-1] )
  508. console.dir(e)
  509. waitForCatch(p);
  510. }
  511. }
  512. else {
  513. // console.log(i + ' Skipping catch : ' + p.result + ' ' + p.chain[i])
  514. i++; __i = i;
  515. waitForThen(p)
  516. }
  517. }
  518. else return p.state = PromiseClass.FULFILLED;
  519. }
  520. function waitForCatch(p) {
  521. if(i < p.chain.length) {
  522. if(p.chain[i].isCatch) {
  523. console.log('chain idx : ' + i + ' Executing : catch : ' + p.result + ' ' + p.chain[i])
  524. try {
  525. p.result = p.chain[i](__e);
  526. if(PromiseClass.resolve(p.result) === p.result) {
  527. p.result.start()
  528. waitForResult(p.result, function(r){
  529. p.result = r; i++; __i = i;
  530. })
  531. waitForThen(p)
  532. }
  533. else {
  534. p.result = r; i++; __i = i;
  535. waitForThen(p)
  536. }
  537. }
  538. catch(e){ i++; __i = i;; __e = e; waitForCatch(p) }
  539. }
  540. else {
  541. i++; __i = i;
  542. waitForCatch(p)
  543. }
  544. }
  545. else return p.state = PromiseClass.REJECTED
  546. }
  547. waitForThen(p);
  548. }
  549. __processchain(r)
  550. }
  551. var create = function(fn){
  552. var p = {
  553. then : function(thenfn){
  554. // console.log('Adding then')
  555. thenfn.isThen = true
  556. // if(Object.prototype.toString.call(p.chain) !== '[object Array]') console.dir(p.chain)
  557. p.chain.push(thenfn)
  558. return p;
  559. }
  560. , 'catch' : function(catchfn) {
  561. catchfn.isCatch = true
  562. p.chain.push(catchfn)
  563. return p;
  564. }
  565. , start : function(){
  566. if(this.started) {
  567. console.error('Cannot start more than once...')
  568. return p
  569. };
  570. this.started = true;
  571. this.fn = fn;
  572. try { fn( function(r){
  573. // console.log('calling presolve in starter ')
  574. p.resolve(r) } , function(r){ p.reject(r) } ) }
  575. catch(e){
  576. // console.log('start catch : ' + e)
  577. // console.log('p.chain.length : ' + p.chain.length)
  578. // // console.dir(p)
  579. // console.dir(e)
  580. // console.log(fn)
  581. p.reject(e)
  582. }
  583. return p
  584. }
  585. , state : PromiseClass.PENDING
  586. , chain : []
  587. , reject : reject
  588. , resolve : resolve
  589. , processchain : processchain
  590. }
  591. p.chain.forEach = forEach;
  592. return p;
  593. }
  594. var PromiseClass = function(fn /*, donotstart */){
  595. var p = create(fn)
  596. // if(!donotstart) {
  597. // wait(function(){
  598. // console.log('p.chain.length' + p.chain.length)
  599. // p.start() } , 500) // Bind and setTImeout is not supported by JScript
  600. // }
  601. return p
  602. }
  603. PromiseClass.PENDING = 1
  604. PromiseClass.FULFILLED = 2
  605. PromiseClass.REJECTED = 3
  606. // PromiseClass.STARTED = 4
  607. PromiseClass.isSETTLED = function(p){ p.state === PromiseClass.FULFILLED || p.state === PromiseClass.REJECTED }
  608. PromiseClass.resolve = function(v){
  609. if(v && v.then) return v;
  610. var p = create(function(resolve, reject){
  611. resolve(v)
  612. });
  613. // console.log('p.chain in resolve. length ' + p.chain.length)
  614. // p.result = v;
  615. // wait(function(){ p.processchain(v) }, 0)
  616. return p;
  617. }
  618. function waitForResult(p, cb){
  619. if(!p) return cb(p)
  620. if(p.state !== PromiseClass.PENDING) cb(p.result)
  621. // console.log(p.state + ' Waiting for ..... ' + p.runFile)
  622. if(p.runFile && false) {
  623. while(!existsSync(p.runFile) && p.state === PromiseClass.PENDING) {
  624. console.log('Waiting for ResultFle'); wait(cb, 500)
  625. }
  626. cb(p.result)
  627. }
  628. else {
  629. // while(p.state === PromiseClass.PENDING) {
  630. // console.log('Waiting for Result')
  631. function waiter(){
  632. // console.log(p.result)
  633. if(p.state === PromiseClass.PENDING) wait(waiter, 500);
  634. else return cb(p.result)
  635. }
  636. wait(waiter, 500)
  637. // }
  638. }
  639. }
  640. PromiseClass.all = any; // Serialized...
  641. PromiseClass.__all = function(arr){
  642. arr.forEach = forEach;
  643. var resultPs = [];
  644. var results = [];
  645. console.log('All : ' + arr.length)
  646. var pAll = new PromiseClass(function(resolve, reject){
  647. console.log('All started : ' + pAll)
  648. // console.dir(pAll)
  649. arr.forEach(function(p){
  650. if(!p.then) { var pfn = p;
  651. p = new PromiseClass(function(resolve, reject){
  652. try{
  653. resolve(pfn())
  654. }
  655. catch(e){
  656. reject(e)
  657. }
  658. })
  659. p.start()
  660. }
  661. else {
  662. // !p.start ? p.start = function(){return p} : null
  663. // p.start()
  664. // .then( function(){ waitForResult(p, function(r){ results.push(r) }) })
  665. }
  666. resultPs.push(p)
  667. // waitForResult(p, function(r){ results.push(r) })
  668. })
  669. // PB : TODO -- This is the same as processchain!!!
  670. var allwaitr = function(){
  671. var allResolved = true
  672. console.log('resultPs : ' + resultPs.length)
  673. for(var rIdx =0; rIdx < resultPs.length; rIdx++ ){
  674. if(resultPs[rIdx]) {
  675. allResolved = false
  676. waitForResult(resultPs[rIdx], function(r){
  677. if(Promise.resolve(r) !== r) results[rIdx] = r; resultPs[rIdx] = null;
  678. })
  679. break;
  680. }
  681. }
  682. if(allResolved) {
  683. // console.log('All Reseloved')
  684. // console.dir(results)
  685. resolve(results)
  686. }
  687. else wait(allwaitr, 500)
  688. }
  689. wait(allwaitr, 500)
  690. })
  691. // pAll.chain = arr;
  692. return pAll
  693. }
  694. // PromiseClass.resolve = overrides.resolve;
  695. Promise = PromiseClass;
  696. return PromiseClass;
  697. }
  698. }
  699. function __main( selectedinstance ){
  700. var downloadsdir = selectedinstance.root + '/Downloads';
  701. var callsheltask = function(args) { return function() { return nodeShellExec.apply(null, args) } }
  702. var gitUser = 'guest';
  703. var gitEmail = 'guest@bbh.org.in';
  704. var BUILD_VERSION = '[VI]Version: {version} - built on {date}[/VI]';
  705. function getVersion() { return BUILD_VERSION; }
  706. console.log(getVersion())
  707. function ensureDirectoryExistence(filePath) {
  708. var dirname = path.dirname(filePath);
  709. if (existsSyncFolder(dirname)) {
  710. return filePath;
  711. }
  712. ensureDirectoryExistence(dirname);
  713. fs.mkdirSync(dirname);
  714. return filePath;
  715. }
  716. var getTaskCheckExists = function(command, options) {
  717. options = options || {}
  718. return function() {
  719. var runFile = path.normalize(selectedinstance.root + '/.elxr/run-' + runtimestamp + '/' + stampedFilePfx(new Date()) + 'where' + command + "out.txt");
  720. var p = nodeShellExec.apply(null, ['cmd', ['/c', 'where', command], { runFile : runFile } ])
  721. p.runFile = runFile;
  722. if (options.ignorefailures) {
  723. return p.then(function(v) {
  724. // WScript.Echo('firstThen ' + v);
  725. return v })['catch']( function(e) {
  726. console.error(e);
  727. // Ignore. Not a major error if where command fails !!!
  728. throw e;
  729. })
  730. }
  731. else return p.then(function() {
  732. // WScript.Echo('firstThen ddd');
  733. return v });
  734. }
  735. }
  736. function verifyAndInstallPrerequisites() {
  737. fs.writeFileSync(ensureDirectoryExistence(downloadsdir + '/readme.txt'), getVersion() + ' Your local downloads for this instance');
  738. var downloadbatch =
  739. "::************************************************************************** \r\n \
  740. :Download_ <url> <File> \r\n \
  741. Powershell.exe ^\r\n \
  742. $AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'; ^\r\n \
  743. [System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols; ^\r\n \
  744. (New-Object System.Net.WebClient).DownloadFile('%1','%2') \r\n \
  745. exit /b \r\n \
  746. ::**************************************************************************";
  747. ensureDirectoryExistence(path.normalize(selectedinstance.root + '/.elxr/run-' + runtimestamp + '/readme.txt'))
  748. fs.writeFileSync(path.normalize(selectedinstance.root + '/.elxr/run-' + runtimestamp + '/download.bat'), downloadbatch);
  749. var downloadtasks = [];
  750. var installtasks = [];
  751. prerequisites.forEach(function(preq) {
  752. if(!all && preq.optional) return
  753. var p = preq.exists().then(function(exists) {
  754. if (exists) console.log( preq.shellcmd + ' exists');
  755. else {
  756. console.log(exists)
  757. console.log(preq.shellcmd + ' is not installed');
  758. return preq.preinstallsteps().then(function(){
  759. // console.log(' task.install : ' + preq.install)
  760. installtasks.push( function(){ return preq.install() } );
  761. })
  762. }
  763. })
  764. // .then(function(res){ console.log( 'preinstallsteps ' + res)});
  765. downloadtasks.push( p )
  766. });
  767. // console.log('downloadtasks')
  768. // console.dir(downloadtasks[0])
  769. var p = Promise.all(downloadtasks).then(function(){
  770. // console.log('calling install tasks : ' + installtasks.length)
  771. return any(installtasks) })
  772. // console.log('Promise.all.chain : ' + p.chain)
  773. return p
  774. }
  775. // var choiceHandler = function(choices, choice) {
  776. // console.log('chosen : ' + choice)
  777. // var decision = choices['d'];
  778. // if (choice && choice === 'd' || !choice) {
  779. // decision = choices['d']
  780. // }
  781. // else if (isNaN((+choice))) {
  782. // decision = choice
  783. // }
  784. // else decision = choices[choice-1]
  785. // if(!decision) throw 'Invalid selection : ' + decision
  786. // return decision
  787. // }
  788. // prereq definition helpers. We can't do proper inheritance in cscript. So fallback to global functions.
  789. function exists(next){
  790. var self = this;
  791. console.log('checking existence of ' + self.shellcmd)
  792. return getTaskCheckExists(self.shellcmd, { ignorefailures: true })().then(function(exists) {
  793. // console.log('-------------exists=======================')
  794. // console.dir(exists)
  795. // console.log(exists + ' ' + self.shellcmd + ' exists')
  796. if(exists && exists.messages.join(' ').indexOf(self.shellcmd) > -1 ) {
  797. return true;
  798. }
  799. else return false
  800. })['catch'](function(e){
  801. // console.log('-------------exists catch=======================')
  802. console.dir(e)
  803. return false;
  804. })
  805. }
  806. function unique(arr) {
  807. var hash = {}, result = [];
  808. for ( var i = 0, l = arr.length; i < l; ++i ) {
  809. if ( !hash.hasOwnProperty(arr[i]) ) { //it works with objects! in FF, at least
  810. hash[ arr[i] ] = true;
  811. result.push(arr[i]);
  812. }
  813. }
  814. return result;
  815. }
  816. // var ENV = Object.assign({}, process.env); // Shallow clone it.
  817. var WshShell = WScript.CreateObject("WScript.Shell")
  818. var ENV = WshShell.Environment("Process")
  819. // WScript.echo( ENV("Path") )
  820. function sysAddPathVar(path){
  821. return true; // PB : TODO -- Not yet enabled. Remove sys path from path before saving.
  822. // Object.assign({
  823. // inherit: true, shell: true, env: ENV, title: `${command} ${args}`
  824. // }, options)
  825. // var newpath = ENV("Path").split(';');
  826. // newpath = Array.from(new Set(newpath.push(path))).join(';')
  827. var newpath = [];
  828. newpath.push(path)
  829. newpath = unique(newpath).join(';')
  830. // path.split(';').forEach(pel => { var kv = pel.split('='); kv[0] === key ? null : newpath.push(pel); } )
  831. return any([nodeShellExec('setx', [/*'/m',*/ 'PATH', '"%PATH%;' + newpath + '"' ])
  832. // , nodeShellExec('set', [/*'/m',*/ 'PATH', '"%PATH%;' + newpath + '"' ])
  833. ] );
  834. }
  835. var prerequisites = [
  836. {
  837. shellcmd: 'git',
  838. url: 'https://github.com/git-for-windows/git/releases/download/v2.33.0.windows.2/Git-2.33.0.2-64-bit.exe'
  839. , installer: 'Git-2.33.0.2-64-bit.exe'
  840. , installcmd: ['cmd', ['/c', 'start',
  841. '/WAIT', downloadsdir + '/' + 'Git-2.33.0.2-64-bit.exe'
  842. , '/VERYSILENT'
  843. // , '/MERGETASKS=!runcode' // This is required only for vscode...
  844. ]]
  845. , preinstallsteps: function() {
  846. var self = this;
  847. console.log('Git preinstall steps')
  848. var steps = [];
  849. steps.push(
  850. function(){
  851. // console.log('cli prompt steps')
  852. var choices = { 0 : 'guest', 1 : 'chessdemo' }
  853. return cli.prompt(choices, 'git user name', gitUser).then(function(choice){ gitUser = choice } )
  854. }
  855. )
  856. steps.push(
  857. function(){
  858. var choices = { 0 : 'guest@bbh.org.in', 1 : 'chessdemo@bbh.org.in' }
  859. return cli.prompt(choices, 'git user email', gitEmail).then(function(choice){ gitEmail = choice })
  860. }
  861. )
  862. steps.push(
  863. function(){
  864. if (!existsSync(downloadsdir + '/' + self.installer)) {
  865. return nodeShellExec(selectedinstance.root + '/.elxr/run-' + runtimestamp + '/download.bat', [self.url, downloadsdir + '/' + self.installer])
  866. }
  867. else {
  868. console.log(self.installer + ' Already exits Download skipped.')
  869. return Promise.resolve(true)
  870. }
  871. }
  872. )
  873. return any(steps)
  874. // return any([any(steps), any(prompts)])
  875. }
  876. , installsteps: function () {
  877. var self = this;
  878. console.log('Git Installsteps called')
  879. var ifns = [self.installcmd]
  880. if(!ifns.map) ifns.map = map;
  881. return any(ifns.map(callsheltask))['catch'](function(e){
  882. if(e.code === 1602) {
  883. console.warn("Installation was probably cancelled.")
  884. }
  885. else throw e
  886. })
  887. }
  888. , postinstallsteps: function(){
  889. // PB : TODO -- Detect failure or cancellation before attenpting postinstall steps...
  890. var steps = [];
  891. steps.push(
  892. function(){
  893. var choices = { 0 : 'guest', 1 : 'chessdemo' }
  894. return cli.prompt(choices, 'git user name', gitUser).then(function(choice){ gitUser = choice } )
  895. }
  896. )
  897. steps.push(
  898. function(){
  899. var choices = { 0 : 'guest@bbh.org.in', 1 : 'chessdemo@bbh.org.in' }
  900. return cli.prompt(choices, 'git user email', gitEmail).then(function(choice){ gitEmail = choice })
  901. }
  902. )
  903. return any(steps).then(function(){
  904. var steps = [
  905. ['git', ['config', '--global', '--add', 'user.name', gitUser]]
  906. , ['git', ['config', '--global', '--add', 'user.email', gitEmail]]
  907. ]
  908. if(!steps.map) steps.map = map;
  909. return any(steps.map(callsheltask)).then(function(){
  910. })
  911. });
  912. }
  913. , install: function () {
  914. var self = this;
  915. console.log('Git Install called')
  916. return any([ /*self.preinstallsteps,*/ function(){ return self.installsteps() }, function(){ return self.postinstallsteps() } ])
  917. }
  918. , verifyAndInstall : function(){
  919. var self = this;
  920. return self.exists().then( function(exits) {
  921. if(exists) return self.getUser(null, function(){ return self.postinstallsteps() } )
  922. else return self.install();
  923. })
  924. }
  925. , exists : exists
  926. , getUser : function(repo, onNoResult){
  927. onNoResult = onNoResult || function(){return false}
  928. var globalOrLocal = '--global';
  929. if(!repo) globalOrLocal = '--global';
  930. else globalOrLocal = '--local'
  931. var fns = [['git', ['config', globalOrLocal, '--get-all', 'user.name']]]
  932. if(!ifns.map) ifns.map = map;
  933. return any(fns.map(callsheltask)).then(function(result){
  934. // not yet configured.
  935. if(!result.success) return onNoResult()
  936. else {
  937. var users = result.messages[0].trim().split('\n');
  938. if(users.length === 0 ||
  939. users.length === 1 && users[0] === 'guest') {
  940. return onNoResult()
  941. }
  942. else return users[0]; // PB : TODO == We should probably prompt with all the users available for selection !
  943. }
  944. })
  945. ['catch'](function(e){
  946. console.log(e)
  947. return onNoResult()
  948. })
  949. }
  950. }
  951. ,
  952. {
  953. shellcmd: 'node',
  954. url: 'https://nodejs.org/dist/v14.17.6/node-v14.17.6-x64.msi'
  955. , installer: 'node-v14.17.3-x64.msi'
  956. , installcmd: ['MSIEXEC.exe', ['/i'
  957. , path.normalize(downloadsdir + '/' + 'node-v14.17.3-x64.msi')
  958. , 'ACCEPT=YES', '/passive']]
  959. , install : function() {
  960. var self = this;
  961. var ifns = [self.installcmd]
  962. if(!ifns.map) ifns.map = map;
  963. return any(ifns.map(callsheltask))['catch'](function(e){
  964. if(e.code === 1602) {
  965. console.warn("Installation was probably cancelled.")
  966. }
  967. else throw e
  968. })
  969. }
  970. , exists : exists
  971. , preinstallsteps: function() {
  972. var self = this;
  973. console.log('Node preinstall steps')
  974. var steps = [];
  975. steps.push(
  976. function(){
  977. if (!existsSync(downloadsdir + '/' + self.installer)) {
  978. return nodeShellExec(selectedinstance.root + '/.elxr/run-' + runtimestamp + '/download.bat', [self.url, downloadsdir + '/' + self.installer]
  979. , { waitmsg : 'downloading node please wait' })
  980. }
  981. else {
  982. console.log(self.installer + ' Already exits Download skipped.')
  983. return Promise.resolve(true)
  984. }
  985. }
  986. )
  987. return any(steps)
  988. // return any([any(steps), any(prompts)])
  989. }
  990. }
  991. , {
  992. shellcmd: 'python2'
  993. , optional : true
  994. , url: 'https://www.python.org/ftp/python/2.7.18/python-2.7.18.amd64.msi'
  995. , installer: 'python-2.7.18.amd64.msi'
  996. , installcmd: ['MSIEXEC.exe', ['/i'
  997. , path.normalize(downloadsdir + '/' + 'python-2.7.18.amd64.msi')
  998. , 'ACCEPT=YES', '/passive']]
  999. , preinstallsteps : function() { return Promise.resolve(true) }
  1000. , install : function() {
  1001. var self = this;
  1002. var ifns = [self.installcmd]
  1003. if(!ifns.map) ifns.map = map;
  1004. console.log('Installing')
  1005. return any(ifns.map(callsheltask))['catch'](function(e){
  1006. if(e.code === 1602) {
  1007. console.warn("Installation was probably cancelled.")
  1008. }
  1009. else throw e
  1010. }).then(function(){
  1011. return self.postinstallsteps()
  1012. })
  1013. }
  1014. , postinstallsteps : function() { return sysAddPathVar('%USERPROFILE%\\AppData/Local\\Microsoft\\WindowsApps') }
  1015. , exists : exists
  1016. }
  1017. , {
  1018. shellcmd: 'code'
  1019. , optional : true
  1020. , url: 'https://vscode-update.azurewebsites.net/latest/win32-x64/stable'
  1021. , installer: 'vscode-win32-x64-latest-stable.exe'
  1022. , installcmd: ['cmd', ['/c', 'start',
  1023. '/WAIT', downloadsdir + '/' + 'Git-2.33.0.2-64-bit.exe'
  1024. , '/VERYSILENT'
  1025. // , '/MERGETASKS=!runcode' // This is required only for vscode...
  1026. ]]
  1027. , preinstallsteps : function() { return Promise.resolve(true) }
  1028. , install : function() {
  1029. var self = this;
  1030. var ifns = [self.installcmd]
  1031. if(!ifns.map) ifns.map = map;
  1032. console.log('Installing')
  1033. return any(ifns.map(callsheltask))['catch'](function(e){
  1034. if(e.code === 1602) {
  1035. console.warn("Installation was probably cancelled.")
  1036. }
  1037. else throw e
  1038. }).then(function(){
  1039. return self.postinstallsteps()
  1040. })
  1041. }
  1042. , postinstallsteps : function() { return sysAddPathVar('%USERPROFILE%\\AppData/Local\\Microsoft\\WindowsApps') }
  1043. , exists : exists
  1044. }
  1045. , {
  1046. shellcmd: 'elxr'
  1047. , installcmd: [ isWin() ? 'npm.cmd' : 'npm' , ['link'], { cwd : selectedinstance.root + '\\elxr' /* cwd should be the cloned dir*/}]
  1048. , preinstallsteps: function() {
  1049. var self = this;
  1050. console.log('Elxr preinstall steps')
  1051. var steps = [];
  1052. steps.push(
  1053. function(){
  1054. console.log('Elxr PreInstallsteps called')
  1055. var ifns = [ ['git', ['clone', 'http://git.bbh/chess\\elxr'] ] ]
  1056. if(existsSyncFolder( selectedinstance.root + '\\elxr')) {
  1057. if(existsSyncFolder( selectedinstance.root + '\\elxr\\.git')) {
  1058. // PB : TODO -- use a elxr guid signature to detect more reliably folders named the same that is not us.
  1059. ifns = [ ['git', ['pull'], { cwd : selectedinstance.root + '\\elxr' } ] ]
  1060. }
  1061. else {
  1062. throw 'elxr subfolder not recognized as a git repository. Please cleanup and continue.'
  1063. }
  1064. }
  1065. else console.log(selectedinstance.root + '\\elxr' + ' NOT FOUND ')
  1066. if(!ifns.map) ifns.map = map;
  1067. return any(ifns.map(callsheltask))['catch'](function(e){
  1068. if(e.code === 1602) {
  1069. console.warn("Installation was probably cancelled.")
  1070. }
  1071. else throw e
  1072. })
  1073. }
  1074. )
  1075. return any([any(steps)])
  1076. }
  1077. , installsteps: function () {
  1078. var self = this;
  1079. console.log('Elxr Installsteps called')
  1080. var ifns = [self.installcmd]
  1081. if(!ifns.map) ifns.map = map;
  1082. return any(ifns.map(callsheltask))['catch'](function(e){
  1083. if(e.code === 1602) {
  1084. console.warn("Installation was probably cancelled.")
  1085. }
  1086. else throw e
  1087. })
  1088. }
  1089. , install: function () {
  1090. var self = this;
  1091. console.log('Elxr Install called')
  1092. return any([ /*self.preinstallsteps,*/ function(){ return self.installsteps() } ])
  1093. }
  1094. // , exists : function(){
  1095. // console.log('Elxr PreInstallsteps called')
  1096. // var ifns = [ ['git', ['clone', 'http://git.bbh/chess\\elxr'] ] ]
  1097. // if(existsSyncFolder( selectedinstance.root + '\\elxr')) {
  1098. // if(existsSyncFolder( selectedinstance.root + '\\elxr\\.git')) {
  1099. // // PB : TODO -- use a elxr guid signature to detect more reliably folders named the same that is not us.
  1100. // ifns = [ ['git', ['pull'], { cwd : selectedinstance.root + '\\elxr' } ] ]
  1101. // }
  1102. // else {
  1103. // throw 'elxr subfolder not recognized as a git repository. Please cleanup and continue.'
  1104. // }
  1105. // }
  1106. // else console.log(selectedinstance.root + '\\elxr' + ' NOT FOUND ')
  1107. // if(!ifns.map) ifns.map = map;
  1108. // return any(ifns.map(callsheltask))['catch'](function(e){
  1109. // if(e.code === 1602) {
  1110. // console.warn("Installation was probably cancelled.")
  1111. // }
  1112. // else throw e
  1113. // })
  1114. // }
  1115. , exists : exists
  1116. }
  1117. ]
  1118. if(!prerequisites.forEach) prerequisites.forEach = forEach;
  1119. // nodeShellExec(selectedinstance.root + '/.elxr/run-' + '1629889572461' + '/download.bat'
  1120. // , ['https://github.com/git-for-windows/git/releases/download/v2.31.0.windows.1/Git-2.32.0.2-64-bit.exe'
  1121. // , downloadsdir + '/' + 'Git-2.32.0.2-64-bit.exe']).start()
  1122. promises.push(verifyAndInstallPrerequisites())
  1123. startPromises();
  1124. }