An interactive command-line interface (CLI) tool to help you install, use, and administer an AO instance.
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.

224 lines
7.0 KiB

// Functions related to OS and installing software
import chalk from 'chalk'
import { execSync } from 'child_process'
// Detects the operating system we are running on
let distro
export function detectOS() {
if(distro) {
return distro
}
try {
execSync('[ -f "/etc/debian_version" ]')
distro = 'debian'
console.log(`${greenChalk('Debian')}, Ubuntu, or Raspbian OS detected.`)
} catch(err) {}
try {
execSync('[ -f "/etc/arch-release" ]')
distro = 'arch'
console.log(`${greenChalk('Arch or Manjaro-based')} OS detected.`)
} catch(err) {}
try {
execSync('[ -f "/etc/fedora-release" ]')
distro = 'fedora'
console.log(`${greenChalk('Fedora')} OS detected.`)
} catch(err) {}
try {
execSync('[ $(uname | grep -c "Darwin") -eq 1 ]')
distro = 'mac'
console.log(`${greenChalk('MacOS')} detected.`)
} catch(err) {}
if(!distro) {
console.log("Your OS was not recognized, sorry.")
process.exit(1)
}
return distro
}
// Runs the correct command to update all your software for any recognized OS
export function updateSoftware() {
detectOS()
if(!distro) {
console.log("Your OS was not recognized, so nothing was updated, sorry.")
return false
}
console.log('Updating your software from repositories...')
console.log(`(You may need to input your ${chalk.blue.bold("'sudo' password")} here)`)
switch(distro) {
case 'debian':
execSync('sudo apt update -yqqq && sudo apt autoremove -yqqq && sudo apt upgrade -yqqq')
break
case 'arch':
execSync('sudo pacman -Syu --noconfirm')
// for Manjaro, also do pamac upgrade -a && pamac update --aur --devel to do normal then build all AUR packages (check https://forum.manjaro.org/c/announcements/11 first)
break
case 'fedora':
execSync('sudo dnf update -yqqq 2>/dev/null && && sudo dnf autoremove -yqqq && sudo dnf upgrade -yqqq')
break
case 'mac':
// Install homebrew (todo: if not installed)
execSync('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"')
execSync('install && sudo brew update') // is this right? can it replicate all commands such as update upgrade autoremove?
break
}
return true
}
// Checks if the given package is installed using the standard repo for your detected OS
function isInstalled(packageName, group) {
detectOS()
if(!distro) {
console.log("Your OS was not recognized, so nothing was updated, sorry.")
return false
}
switch(distro) {
case 'debian':
return execSync("dpkg-query -W -f='${Status}' " + packageName + " 2>/dev/null").includes('ok installed')
case 'arch':
try {
if(!group) {
const stdout = execSync("pacman -Qi " + packageName)
if(stdout.includes('was not found')) {
return false
}
} else {
const stdout = execSync("pacman -Qg " + packageName).toString()
if(!stdout.includes(packageName)) {
return false
}
}
return true
} catch(error) {
break
}
case 'fedora':
case 'mac':
}
}
// Uses the standard app repo for your detected OS to install the named package
function installPackage(packageName) {
detectOS()
if(!distro) {
console.log("Your OS was not recognized, so nothing was updated, sorry.")
return false
}
switch(distro) {
case 'debian':
try {
execSync('sudo apt install -y ' + packageName)
return true
} catch(error) {
break
}
case 'arch':
try {
const result = execSync("sudo pacman -S " + packageName + " --noconfirm").toString()
console.log(packageName, 'installed result is', result)
return true
} catch(error) {
break
}
case 'fedora':
case 'mac':
console.log('Install on this OS not yet implemented, sorry.')
}
console.log('Failed to install', packageName + '. Error:', error)
return false
}
// Installs the specified package or packages using the standard repos for your detected OS. Prints console messages if verbose.
function installIfNotInstalled(packageNameOrNames, verbose = true, group = false) {
if(!Array.isArray(packageNameOrNames)) {
if(typeof packageNameOrNames !== 'string') {
if(verbose) console.log('Invalid package name provided. Doing nothing.')
return null
}
packageNameOrNames = [ packageNameOrNames ]
}
let packagesInstalled = 0
let packagesFailed = 0
packageNameOrNames.forEach(packageName => {
if(!isInstalled(packageName, group)) {
const success = installPackage(packageName)
if(success) {
if(verbose) console.log('Installed', packageName + '.')
packagesInstalled++
} else {
if(verbose) console.log('Failed to install', packageName + '.')
packagesFailed++
}
} else {
if(verbose) console.log(packageName, 'already installed.')
}
})
return { installed: packagesInstalled, failed: packagesFailed }
}
// Creates the directories to store the AO's database, memes, manual, and maybe other things, ~/.ao by standard
export function createAoDirectories() {
try {
execSync('mkdir -p $HOME/.ao/memes')
} catch(error) {
console.log('Error creating ~/.ao/memes directory. Maybe it already exists.')
}
}
function installNvm() {
try {
execSync('[ -z $NVM_DIR ]')
execSync('source ~/Alchemy/ingredients/iron && install_nvm')
console.log(`Installed nvm.`)
return true
} catch(err) {
return false
}
}
// Installs core dependencies required by Alchemy and the AO
export function installRequired() {
detectOS()
if(!distro) {
console.log("Your OS was not recognized, so nothing was installed, sorry.")
return false
}
console.log('Installing Alchemy and AO installation process core dependencies (fast if already installed)...')
console.log(`(You may need to input your ${chalk.blue.bold("'sudo' password")} here)`)
// Install on every OS
installIfNotInstalled(['curl', 'wget', 'git', 'make', 'sqlite3', 'python', 'autoconf-archive'])
installNvm()
// Install OS-specific requirements
switch(distro) {
case 'debian':
// Some of these might not be required
installIfNotInstalled(['build-essential', 'zlib1g-dev', 'libtool-bin', 'autoconf', 'automake autotools-dev', 'libgmp-dev', 'libsqlite3-dev', 'python3', 'python3-mako', 'libsodium-dev', 'pkg-config', 'libev-dev', 'libcurl4-gnutls-dev', 'libssl-dev', 'fakeroot', 'devscripts'])
break
case 'arch':
installIfNotInstalled('base-devel', true, true)
installIfNotInstalled(['gmp', 'pkgconf', 'libev', 'python-mako', 'python-pip', 'net-tools', 'zlib', 'libsodium', 'gettext', 'nginx'])
break
case 'fedora':
installIfNotInstalled(['autoconf', 'automake', 'python3', 'python3-mako', 'pkg-config', 'fakeroot', 'devscripts'])
break
}
return true
}
// Sets node to the current version used by the AO
export function setNodeVersion() {
execSync('source ~/Alchemy/ingredients/lead && source ~/Alchemy/ingredients/iron && set_node_to v16.13.0')
}