You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
209 lines
6.9 KiB
209 lines
6.9 KiB
#!/usr/bin/env node |
|
import chalk from 'chalk' |
|
import { execSync } from 'child_process' |
|
|
|
// Import ao-cli core features |
|
import { exitIfRoot, detectOS, updateSoftware } from './scripts/system.js' |
|
import { checkAoEnvFile, aoEnv, setAoEnv, AO_ENV_FILE_PATH } from './ao-lib/settings.js' |
|
import { unicornPortal, asciiArt, clearScreen } from './scripts/console.js' |
|
import { welcome, exclaim, farewell, yesOrNo, promptMenu } from './scripts/welcome.js' |
|
import wander from './scripts/forest.js' |
|
import useAoMenu from './scripts/ao.js' |
|
import aoInstallWizard, { chooseAoVersion, checkAo } from './scripts/wizard.js' |
|
import testsMenu from './scripts/tests.js' |
|
import { headerStyle } from './scripts/styles.js' |
|
import { randomInt } from './ao-lib/util.js' |
|
import './scripts/strings.js' |
|
|
|
// Import AO modular features |
|
import features, { featuresMenu } from './features/index.js' |
|
import manual, { printManualPage, manualFolderAsMenu, AO_MANUAL_PATH } from './features/manual.js' |
|
import aoCli from './features/ao-cli.js' |
|
|
|
const sleep = (ms = 550) => { return new Promise((r) => setTimeout(r, ms)) } |
|
|
|
// Prints the AO Main Menu and executes the user's choice |
|
async function mainMenu() { |
|
//console.log(`\n${headerStyle('AO Main Menu')}\n`) |
|
let mainMenuChoices = [ |
|
{ title: 'AO', description: 'use AO features' }, |
|
{ title: 'Alchemy', description: 'transmute system to gold' }, |
|
{ title: 'Configure', description: 'configure AO features' }, |
|
{ title: 'Manual', description: 'read the manual' }, |
|
{ title: 'Exit', description: 'ESC on any menu' } |
|
] |
|
const answer = await promptMenu(mainMenuChoices, 'AO Main Menu') |
|
let previousChoice |
|
switch(answer) { |
|
case 'AO': |
|
while(await useAoMenu()) {} |
|
break |
|
case 'Alchemy': |
|
while(await adminMenu()) {} |
|
break |
|
case 'Configure': |
|
do { |
|
previousChoice = await featuresMenu(previousChoice) |
|
} while(previousChoice !== false) |
|
break |
|
case 'Manual': |
|
if(!manual.isInstalled()) { |
|
console.log("Downloading the AO manual...") |
|
if(manual.install()) { |
|
console.log("Downloaded the AO Manual from the official git repo via http and saved to", AO_MANUAL_PATH + '.') |
|
} else { |
|
console.log('Failed to download the AO manual, sorry.') |
|
return false |
|
} |
|
} else { |
|
manual.update() |
|
} |
|
await printManualPage(AO_MANUAL_PATH) // Fencepost case - print overview page |
|
do { |
|
previousChoice = await manualFolderAsMenu(AO_MANUAL_PATH, 'AO User Manual', 'Back to Main Menu', previousChoice + 1) |
|
} while(previousChoice !== false) |
|
break |
|
default: |
|
farewell() |
|
await sleep(310) |
|
return false |
|
} |
|
return true |
|
} |
|
|
|
// Prints the AO Admin Menu and executes the user's choice |
|
// Maybe Alchemy menu should be installation and update, and admin menu should be more configuration & AO member admin |
|
async function adminMenu() { |
|
const adminChoices = [ |
|
{ title: 'Check AO install', value: 'check_AO' }, |
|
'Update everything', |
|
'Update system software', |
|
//'Update AO', |
|
//{ name: 'Install AO prerequisites', value: 'prereqs' }, // move to feature module? calls installRequired() |
|
'AO install wizard', |
|
//'Switch AO target server', |
|
//'Switch AO database', |
|
'Switch AO version', |
|
//'Check AO service', |
|
//'Start/Stop AO service', |
|
//'Import/export state/decks', |
|
//'Watch logs now', |
|
'Tests', |
|
//'Update remote AOs', |
|
'Back to Main Menu' |
|
] |
|
const answer = await promptMenu(adminChoices, 'System Alchemy') |
|
switch(answer) { |
|
case 'check_AO': |
|
await checkAo() |
|
break |
|
case 'Update everything': |
|
// todo: go through the stuff in wizard and system and files and see if it can be moved to feature modules so it doesn't have to go here as an exceptional upgrade case |
|
const featureEntries = Object.entries(features) |
|
for(let i = 0; i < featureEntries.length; i++) { |
|
const feature = featureEntries[i][1] |
|
console.log('feature name is', feature.name) |
|
const status = feature.status() |
|
if((feature.hasOwnProperty('isInstalled') && feature.isInstalled()) || (['installed', 'enabled', 'running', 'synced'].includes(status))) { |
|
console.log('Updating' + feature.name + '...') |
|
if(feature.hasOwnProperty('upgrade')) { |
|
await feature.upgrade() |
|
} |
|
} |
|
} |
|
break |
|
case 'Update system software': |
|
updateSoftware() |
|
break |
|
case 'AO install wizard': |
|
await aoInstallWizard() |
|
break |
|
case 'Switch AO version': |
|
await chooseAoVersion() |
|
break |
|
case 'Switch AO target server': |
|
case 'Import/Export state/decks': |
|
case 'Watch logs now': |
|
case 'Update remote AOs': |
|
console.log("Not yet implemented.") |
|
break |
|
case 'Tests': |
|
while(await testsMenu()) {} |
|
break |
|
default: |
|
return false |
|
} |
|
return true |
|
} |
|
|
|
// Returns false if a flag means the program should now terminate |
|
// -v Print version info |
|
async function handleArgs(args) { |
|
switch (args[0]) { |
|
case '--version': |
|
case '-v': |
|
console.log(await aoCli.version()) |
|
return false |
|
case '--interstitial': |
|
case '-cd': |
|
// Don't say a message every time or it will annoy everybody |
|
if(randomInt(0, 6) === 0) { |
|
console.log(await wander(args[1])) |
|
} |
|
return false |
|
} |
|
return true |
|
} |
|
|
|
// Main entry point |
|
async function main() { |
|
// Print version info etc. no matter what |
|
const nodePath = process.argv[0] |
|
const aoCliPath = process.argv[1] |
|
const args = process.argv.slice(2) |
|
const shouldTerminate = !await handleArgs(args) |
|
if(shouldTerminate) { |
|
process.exit(0) |
|
} |
|
|
|
// No root allowed |
|
exitIfRoot() |
|
|
|
// Loading screen, display some quick info during the fun animation |
|
console.log('ao-cli v' + (await aoCli.version())) |
|
const DISTRO = aoEnv('DISTRO') |
|
if(!DISTRO) { |
|
setAoEnv('DISTRO', detectOS()) |
|
} |
|
const friendlyEnvPath = AO_ENV_FILE_PATH.replace(/^\/home\/\w+/, '~') |
|
if(checkAoEnvFile()) { |
|
console.log(friendlyEnvPath, 'exists') |
|
} else { |
|
console.log(friendlyEnvPath, 'does not exist') |
|
} |
|
await unicornPortal(650) |
|
|
|
if(!aoEnv('AO_FIRST_RUN')) { |
|
clearScreen() |
|
asciiArt() |
|
console.log('\n' + exclaim(), 'It looks like this is the first time you\'re running ao-cli on this computer! ao-cli stands for Autonomous Organization-Command Line Interface.\n\nWould you like to run the AO install wizard? It will walk you through setting up an AO server instance so you can use the AO on this computer as a full node. (Press Ctrl-C at any time to exit.)\n') |
|
const pleaseInstall = await yesOrNo('Start the AO install wizard?', true) |
|
setAoEnv('AO_FIRST_RUN', true) |
|
if(pleaseInstall) { |
|
await aoInstallWizard() |
|
} else { |
|
console.log('You can start the AO install wizard at any time from the Configure menu.') |
|
} |
|
} |
|
|
|
// Main AO title screen and flavor text |
|
clearScreen() |
|
asciiArt() |
|
await welcome() |
|
|
|
// Main loop |
|
while(await mainMenu()) {} |
|
process.exit(0) |
|
} |
|
|
|
await main()
|
|
|