// 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' )
}