| @@ -2069,12 +2069,14 @@ var hasElxr = function(path, options, cb) { | |||
| var hasElxrSync = function(path){ return hasElxr(path, { sync :true}); } | |||
| var detectfromroot = function(root){ | |||
| return { root, node_env : path.basename(path.dirname(root)), instanceName : path.basename( path.dirname(path.dirname(root)) ) } | |||
| return { root, node_env : path.basename(root), instanceName : path.basename( path.dirname(root) ) } | |||
| } | |||
| var detectinstances = function () { | |||
| console.log(`launchpath = ${launchpath}`) | |||
| console.log(`thisscriptdir = ${thisscriptdir}`) | |||
| // PB : TODO -- !Postpone this. | |||
| console.log(`instanceroot = ${instanceroot}`) // Not yet confirmed... | |||
| // Note : Paths should already be normalized fefore this. | |||
| @@ -2088,25 +2090,41 @@ var detectinstances = function () { | |||
| // We need a reference to the root director for elxr cli to be properly oriented. | |||
| if (( elxrCliExists && path.normalize(launchpath + '/elxr')) === thisscriptdir) { | |||
| // We were run from the proper root with elxr cli in the subfolder. | |||
| console.log(`Instance Path : ${root}`) | |||
| instanceroot = root = launchpath; | |||
| instanceoptions.splice( 0, 0, dedetected = { root }) | |||
| instanceoptions.splice( 0, 0, detected = { root }) | |||
| instanceoptions.splice( 0, 0, detectfromroot(root)) | |||
| } | |||
| else { | |||
| if (launchpath === thisscriptdir) { | |||
| if(path.normalize(launchpath + '/elxr') === thisscriptdir) { | |||
| // elxrCliExists is false -- and yet thiscriptdir is still proper. | |||
| // PB : TODO -- Maybe a warning / abort if for some reason this scriptdir should not be taken over... | |||
| console.error('Warning : detected thisscriptdir as elxr subfolder but not recognized as elixir. git updates might fail.') | |||
| instanceroot = root = launchpath; | |||
| instanceoptions.splice( 0, 0, detected = { root }) | |||
| instanceoptions.splice( 0, 0, detectfromroot(root)) | |||
| } | |||
| else if (launchpath === thisscriptdir) { | |||
| var parentHasElxr = hasElxrSync(launchpath + '/..') | |||
| // PB : TODO -- verify if we have .elxr folder in the parent... | |||
| if(!parentHasElxr) { | |||
| // ! thisscriptdir is not elxr. | |||
| console.error('Invalid run location in subfolder that looks like elxr. We should probably abort as elxr will not sync.') | |||
| } | |||
| // Same directory doesn't mean we are being run from elxr sub directory. | |||
| // In standalone build script we may or not be in the same location. | |||
| if (BUILD_VERSION.indexOf('Version: {version} - built on {date}') > -1) { | |||
| // Unbuilt therefore we are in the elxr directory. | |||
| // Unbuilt therefore we are in the elxr sub directory. | |||
| instanceroot = root = path.normalize(launchpath + '/..'); | |||
| instanceoptions.splice( 0, 0, dedetected = { root }) | |||
| instanceoptions.splice( 0, 0, detectfromroot(root)) | |||
| instanceoptions.splice( 0, 0, detected = { root }); | |||
| instanceoptions.splice( 0, 0, detectfromroot(root)); | |||
| } | |||
| else { | |||
| // Built version. | |||
| // We could have been run from the elxr subfolder. Highly likely that the built version isn't the full elxr. | |||
| if(hasElxrSync(launchpath + '/..')) { | |||
| if(parentHasElxr) { | |||
| // Built version was run from the full elxr subfolder. Should work | |||
| // PB : TODO -- but we should switch to the full version... | |||
| instanceroot = root = path.normalize(launchpath + '/..'); | |||
| @@ -2114,99 +2132,135 @@ var detectinstances = function () { | |||
| instanceoptions.splice( 0, 0, detectfromroot(root)) | |||
| } | |||
| else { | |||
| instanceroot = root = launchpath; | |||
| instanceoptions.splice( 0, 0, detected = { root }) | |||
| instanceoptions.splice( 0, 0, detectfromroot(root)) | |||
| // Assume current launchpath is a new instance and create. | |||
| // Figure out the instnace name and environment from parent folders as an alternative option with confirmation if not provided in the arguments. | |||
| if(clioverrides.instanceName) { | |||
| if(clioverrides.node_env) { | |||
| instanceroot = root = path.normalize(launchpath + '/' + clioverrides.instanceName + '/' + clioverrides.node_env) | |||
| instanceoptions.splice( 0, 0, detected = { root, instanceName : clioverrides.instanceName, node_env : clioverrides.node_env }) | |||
| // instanceoptions.splice( 0, 0, detectfromroot(root)) // This can be an option but is unnecessary unless a confirmation is provided. | |||
| // also folder names may have no relation to the actual instanceName and instanceType coz we need to have many | |||
| // eg : floder name can be elixir01 but instance name is elixr | |||
| } | |||
| else { | |||
| instanceroot = root = path.normalize(launchpath + '/' + clioverrides.instanceName + '/' + 'development') | |||
| instanceoptions.splice( 0, 0, detected = { root, instanceName : clioverrides.instanceName, node_env : 'development' }) | |||
| instanceoptions.splice( 0, 0, detectfromroot(root)) // A recessive option only. | |||
| } | |||
| } | |||
| else { | |||
| instanceroot = root = launchpath; | |||
| if(clioverrides.node_env) { | |||
| instanceoptions.splice( 0, 0, detected = { root, node_env : clioverrides.node_env }) | |||
| instanceoptions.splice( 0, 0, detectfromroot(root)) | |||
| } | |||
| else { | |||
| // Nothing was specified... We only have one option from root. | |||
| instanceoptions.splice( 0, 0, detected = detectfromroot(launcpath)) | |||
| } | |||
| } | |||
| // if(clioverrides.instanceName) { | |||
| // if(clioverrides.node_env) { | |||
| // instanceroot = root = path.normalize(launchpath + '/' + clioverrides.instanceName + '/' + clioverrides.node_env) | |||
| // instanceoptions.splice( 0, 0, detected = { root, instanceName : clioverrides.instanceName, node_env : clioverrides.node_env }) | |||
| // // instanceoptions.splice( 0, 0, detectfromroot(root)) // This can be an option but is unnecessary unless a confirmation is provided. | |||
| // // also folder names may have no relation to the actual instanceName and instanceType coz we need to have many | |||
| // // eg : floder name can be elixir01 but instance name is elixr | |||
| // } | |||
| // else { | |||
| // instanceroot = root = path.normalize(launchpath + '/' + clioverrides.instanceName + '/' + 'development') | |||
| // instanceoptions.splice( 0, 0, detected = { root, instanceName : clioverrides.instanceName, node_env : 'development' }) | |||
| // instanceoptions.splice( 0, 0, detectfromroot(root)) // A recessive option only. | |||
| // } | |||
| // } | |||
| // else { | |||
| // instanceroot = root = launchpath; | |||
| // if(clioverrides.node_env) { | |||
| // instanceoptions.splice( 0, 0, detected = { root, node_env : clioverrides.node_env }) | |||
| // instanceoptions.splice( 0, 0, detectfromroot(root)) | |||
| // } | |||
| // else { | |||
| // // Nothing was specified... We only have one option from root. | |||
| // instanceoptions.splice( 0, 0, detected = detectfromroot(launcpath)) | |||
| // } | |||
| // } | |||
| } | |||
| } | |||
| } | |||
| else { | |||
| if(elxrCliExists) { | |||
| instanceroot = root = launchpath; | |||
| instanceoptions.splice( 0, 0, detected = { root }) | |||
| instanceoptions.splice( 0, 0, detectfromroot(root)) | |||
| } | |||
| } | |||
| } | |||
| instanceroot = detected.root | |||
| __default.root = root; | |||
| clioverrides.root = clioverrides.root || root; | |||
| // We can expect a .elxr at each level. | |||
| ['' /* instanceroot */, '../' /* instanceTypes or node_env */, '../..' /* instanceNames */]. | |||
| earlyreduce( ( value, p, i, a )=>{ | |||
| var localinstancesPath = `${instanceroot}/${p}.elxr`; | |||
| if(existsSync( localinstancesPath )) { | |||
| try { | |||
| var chessinstances = acquirelocalinstances( { localinstancesPath } ) | |||
| return Object.keys(chessinstances).earlyreduce( ( value, instanceName) => { | |||
| return Object.keys(chessinstances[instanceName]).earlyreduce( (value, instanceType) => { | |||
| if( path.normalize(chessinstances[instanceName][instanceType].root) === path.normalize( instanceroot) ) { | |||
| instanceoptions.splice( 0, 0, chessinstances[instanceName][instanceType]) | |||
| return { | |||
| value : chessinstances[instanceName][instanceType] | |||
| , done : true | |||
| }; | |||
| } | |||
| }) | |||
| }) | |||
| } | |||
| catch(e){ | |||
| return { } | |||
| } | |||
| } | |||
| else return { } | |||
| } | |||
| ) | |||
| // Resolves empty array when No known instances detected. | |||
| return Promise.resolve(instanceoptions) | |||
| }) | |||
| } | |||
| var __interactve_promts = { | |||
| get reposerver(){ | |||
| return cli.prompt(this.reposervers, 'git default repo').then(reposerver => { | |||
| Object.defineProperty(this, 'reposerver', { | |||
| value: reposerver, | |||
| writable: false, | |||
| configurable : true, | |||
| enumerable : true | |||
| }); | |||
| return reposerver | |||
| }) | |||
| } | |||
| , set reposerver(reposerver){ | |||
| Object.defineProperty(this, 'reposerver', { | |||
| value: reposerver, | |||
| writable: false, | |||
| configurable : true, | |||
| enumerable : true | |||
| }); | |||
| return reposerver | |||
| var __interactve_promts = function( selectedinstance ){ | |||
| return { | |||
| runchoice : { | |||
| label : | |||
| `Choose an option : | |||
| d) Install the default chess instance. | |||
| => elxr i chess node_env=development --default | |||
| n) Create your custom new instance interactively | |||
| => elxr i {{instanceName}} node_env={{environment}} | |||
| i) Choose an instance and environment to install | |||
| => elxr i {{instanceName}} node_env={{environment}} | |||
| c) Choose a command to run ( pull, use, i, npmi ... ) <= pull | |||
| => elxr {{cmd}} {{instanceName}} node_env={{environment}} | |||
| h) Help | |||
| q) Quit | |||
| : ` | |||
| , choices : [] | |||
| , defaultchoice : 'c' | |||
| , interpret : function(choice){ | |||
| var imap = { | |||
| d : function(){ | |||
| processedArgs._[0] = 'i' | |||
| selectedinstance.instanceName = processedArgs._[1] = processedArgs._[1] || 'chess' | |||
| selectedinstance.node_env = processedArgs.node_env = (process.env.NODE_ENV && process.env.NODE_ENV.trim()) || processedArgs.node_env || 'development' | |||
| selectedinstance.reposerver = 'https://git.bbh.org.in' | |||
| } | |||
| , n : function() { processedArgs._[0] = 'i' } | |||
| , i : function() { processedArgs._[0] = 'i' } | |||
| , c : function() { cli.prompter.ask(`Enter cmd : | |||
| p) pull | |||
| Default <= p | |||
| : `).then(function (cmd) { | |||
| if (!cmd || cmd === 'p') { | |||
| processedArgs._[0] = 'pull' | |||
| } | |||
| else processedArgs._[0] = cmd | |||
| return cmd; | |||
| }) | |||
| } | |||
| , h : function() { console.log(elxr.help()); process.exit() } // PB : TODO -- Why do we need log. | |||
| , q : function() { process.exit() } | |||
| } | |||
| if(!choice) return imap['c'] | |||
| return imap[choice] ? imap[choice]() : imap['c']; | |||
| } | |||
| } | |||
| , instanceName : { label : `Enter Instance Name ( <= ${selectedinstance.instanceName} ) : `, choices : [], defaultchoice : 'chess'} | |||
| , instanceType : { label : `Enter Instance Type ( <= ${selectedinstance.instanceType} ) : `, choices : [], defaultchoice : 'development'} | |||
| , reposerver : { label : `Enter Instance Name ( <= ${selectedinstance.reposerver} ) : `, choices : [], defaultchoice : 'https://git.bbh.org.in'} | |||
| // get reposerver(){ | |||
| // return cli.prompt(this.reposervers, 'git default repo').then(reposerver => { | |||
| // Object.defineProperty(this, 'reposerver', { | |||
| // value: reposerver, | |||
| // writable: false, | |||
| // configurable : true, | |||
| // enumerable : true | |||
| // }); | |||
| // return reposerver | |||
| // }) | |||
| // } | |||
| // , set reposerver(reposerver){ | |||
| // Object.defineProperty(this, 'reposerver', { | |||
| // value: reposerver, | |||
| // writable: false, | |||
| // configurable : true, | |||
| // enumerable : true | |||
| // }); | |||
| // return reposerver | |||
| // } | |||
| } | |||
| } | |||
| var downloadsdir = '../Downloads'; | |||
| var prerequisites = [ | |||
| { | |||
| @@ -2442,10 +2496,11 @@ function verifyAndInstallPrerequisites() { | |||
| return Promise.all(downloadtasks).then(() => { return any(installtasks) }) | |||
| } | |||
| var getPromptableAsyncPropDescriptor = function(propName, choices, defaultchoise){ | |||
| var getPromptableAsyncPropDescriptor = function(propName, promptable){ | |||
| return { | |||
| get (){ | |||
| return cli.prompt( choices, propName, defaultchoise).then(propValue => { | |||
| return cli.prompt( promptable.choices, promptable.label, promptable.defaultchoice ).then(propValue => { | |||
| propName = promptable.interpret(propValue) | |||
| Object.defineProperty(this, propName, { | |||
| value: propValue, | |||
| writable: false, | |||
| @@ -2473,10 +2528,40 @@ var getPromptableAsyncPropDescriptor = function(propName, choices, defaultchoise | |||
| function acquirelocalinstances(selected){ | |||
| // utils.assign is used to cleanup duplicates... | |||
| var chessinstances = utils.assign(require(path.normalize(selected.root + '/chessinstances.js'))); | |||
| return chessinstances | |||
| } | |||
| function findlocalinstances(chessinstances, instanceoptions){ | |||
| // We can expect a .elxr at each level. | |||
| ['' /* instanceroot */, '../' /* instanceTypes or node_env */, '../..' /* instanceNames */]. | |||
| earlyreduce( ( value, p, i, a )=>{ | |||
| var localinstancesPath = `${instanceroot}/${p}.elxr`; | |||
| if(existsSync( localinstancesPath )) { | |||
| try { | |||
| var chessinstances = acquirelocalinstances( { localinstancesPath } ) | |||
| return Object.keys(chessinstances).earlyreduce( ( value, instanceName) => { | |||
| return Object.keys(chessinstances[instanceName]).earlyreduce( (value, instanceType) => { | |||
| if( path.normalize(chessinstances[instanceName][instanceType].root) === path.normalize( instanceroot) ) { | |||
| instanceoptions.splice( 0, 0, chessinstances[instanceName][instanceType]) | |||
| return { | |||
| value : chessinstances[instanceName][instanceType] | |||
| , done : true | |||
| }; | |||
| } | |||
| }) | |||
| }) | |||
| } | |||
| catch(e){ | |||
| return { } | |||
| } | |||
| } | |||
| else return { } | |||
| } | |||
| ) | |||
| } | |||
| // function updateselection(selected) { selectedinstance = utils.assign(selectedinstance, selected) } | |||
| var selectedinstance = null; | |||
| @@ -2609,17 +2694,50 @@ acquireElevationState().then(() => { | |||
| } | |||
| return detectinstances().then((detectedinstanceoptions)=>{ | |||
| var getchoices = function(){ | |||
| detectedinstanceoptions.splice(0,0, __default) | |||
| var instances = [] | |||
| var reposervers = []; | |||
| var instnaceNames = [] | |||
| var instanceTypes = ['development', 'production']; | |||
| Object.keys( chessinstances).forEach(instanceName => { | |||
| if(instanceName === 'current_run') return; | |||
| Object.keys( chessinstances[instanceName] ).forEach(node_env=>{ | |||
| var instance = chessinstances[instanceName][node_env]; | |||
| reposervers = reposervers.concat(instance.reposervers) | |||
| if(instance.reposerver) reposervers.push(instance.reposerver) | |||
| instances.push(instance) | |||
| instanceTypes.push(instance.node_env) | |||
| instnaceNames.push(instance.instanceName) | |||
| }) | |||
| }) | |||
| instances = instances.concat(detectedinstanceoptions) | |||
| if(promptkeys['instanceName']) instnaceNames.push(selectedinstance['instanceName']) | |||
| if(promptkeys['instanceName']) instnaceNames.push(promptkeys['instanceName']) | |||
| if(selectedinstance['reposervers']) reposervers = reposervers.concat(selectedinstance['reposervers']) | |||
| var choices = { | |||
| 'instanceName' : Array.from( new Set(instnaceNames) ) | |||
| , 'reposerver' : Array.from( new Set(reposervers) ) | |||
| , 'instanceType' : Array.from( new Set(instanceTypes) ) | |||
| } | |||
| return choices; | |||
| } | |||
| // PB : TODO -- Most recent should be at the tip ! at index 0 so utils.reverseassign is required !!! | |||
| selectedinstance = utils.assign( ...detectedinstanceoptions.slice(-2) ) | |||
| promptkeys = utils.assign(promptkeys, { 'instanceName' : clioverrides.instanceName, 'node_env' : clioverrides.node_env }) | |||
| promptkeys = utils.assign(promptkeys, clioverrides) | |||
| if(clioverrides.reconfirm) { | |||
| var reconfirm = { 'instanceName' : selectedinstance['instanceName'] === 'chess' } | |||
| } | |||
| else { var reconfirm = {}; } | |||
| var prompts = []; | |||
| var eachPrompt = function(k, i, a){ | |||
| // No local instances config found. We use a default initialized instance available in selectedinstance | |||
| @@ -2633,61 +2751,48 @@ acquireElevationState().then(() => { | |||
| // We take a snapshot... Shallow.. !! If required deep should be used based on use case. | |||
| // If latest altered state is required we can reerence this directly. | |||
| // var asyncthis = Object.assign(this); | |||
| Object.defineProperty(selectedinstance, k, getPromptableAsyncPropDescriptor(k, choices[k], promptkeys[k] || selectedinstance[k] )); | |||
| promptables[k].choices = choices[k] | |||
| Object.defineProperty(selectedinstance, k, getPromptableAsyncPropDescriptor(k, promptables[k])); | |||
| return await selectedinstance[k] | |||
| }) | |||
| } | |||
| delete promptkeys[k] | |||
| } | |||
| try { | |||
| chessinstances = acquirelocalinstances(selectedinstance); | |||
| initinstances(selectedinstance) | |||
| findlocalinstances(chessinstances, detectedinstanceoptions) | |||
| var todo = Promise.resolve(true); | |||
| var instanceNameChoices = new Set(Object.keys( chessinstances) ) | |||
| instanceNameChoices.delete('current_run') | |||
| instanceNameChoices.add(selectedinstance['instanceName']) | |||
| if(promptkeys['instanceName']) instanceNameChoices.add(promptkeys['instanceName']) | |||
| var choices = { | |||
| 'instanceName' : Array.from(instanceNameChoices) | |||
| , 'reposerver' : selectedinstance['reposervers'] | |||
| } | |||
| Object.keys(__interactve_promts).forEach(eachPrompt, __interactve_promts) | |||
| Object.keys(promptkeys).forEach(eachPrompt, promptkeys) | |||
| var choices = getchoices() | |||
| var promptables = __interactve_promts(selectedinstance) | |||
| Object.keys(promptables).forEach(eachPrompt, selectedinstance) | |||
| todo = any(prompts).then(()=>{ return selectedinstance }) | |||
| var todo = Promise.resolve(true); | |||
| todo = any(prompts).then(()=>{ | |||
| return initinstances(selectedinstance) | |||
| }) | |||
| } | |||
| catch (e) { | |||
| // PB : TODO -- verbose mode warning.. console.warn(e) // Missing chessinstances is not an error... | |||
| initinstances(selectedinstance) | |||
| var instanceNameChoices = new Set(Object.keys( chessinstances) ) | |||
| instanceNameChoices.delete('current_run') | |||
| instanceNameChoices.add(selectedinstance['instanceName']) | |||
| if(promptkeys['instanceName']) instanceNameChoices.add(promptkeys['instanceName']) | |||
| var choices = { | |||
| 'instanceName' : Array.from(instanceNameChoices) | |||
| , 'reposerver' : selectedinstance['reposervers'] | |||
| , 'instanceType' : ['development', 'production'] | |||
| } | |||
| Object.keys(__interactve_promts).forEach(eachPrompt, __interactve_promts) | |||
| Object.keys(promptkeys).forEach(eachPrompt, promptkeys) | |||
| var choices = getchoices() | |||
| var promptables = __interactve_promts(selectedinstance) | |||
| Object.keys(promptables).forEach(eachPrompt, selectedinstance) | |||
| todo = any(prompts).then(()=>{ return selectedinstance }) | |||
| todo = any(prompts).then(()=>{ return initinstances(selectedinstance) }) | |||
| if(!processedArgs._[0] || !selectedinstance.node_env || !selectedinstance.instanceName){ | |||
| // Weve been told what to do. | |||
| // Weve not been told what to do. | |||
| todo = todo.then(() => { return acquireChoices(selectedinstance) }) | |||
| } | |||
| todo = todo.then(() => { | |||
| try { | |||
| chessinstances = acquirelocalinstances(selectedinstance) | |||
| findlocalinstances(chessinstances, detectedinstanceoptions) | |||
| detectedinstanceoptions.splice(0,0, __default) | |||
| initinstances(selectedinstance) | |||
| } | |||
| catch (e) { | |||