// Functions related to OS and installing software import chalk from 'chalk' import { execSync } from 'child_process' // Exits ao-cli if has been run with sudo or while logged in as root/superuser using su export function exitIfRoot() { try { let loggedInUserUnixID = parseInt(execSync('echo $EUID').toString()) if(loggedInUserUnixID === 0) { console.log(`${chalk.red.bold(exclaim())} Seems you're running this script as a superuser.`) console.log('That might cause some issues with permissions and whatnot. Run this script as your default user (without sudo) and I\'ll ask you when I need superuser permissions.') process.exit(1) } } catch(err) { console.log('Error checking whether or not you are root. Continuing but please do not run ao-cli as root or sudo! It will install things with admin privileges and then you won\'t be able to access them.') } } // 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') 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 export 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. export 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 } } // Returns true if npm install (npm i) has been run in the given path, otherwise false. Also returns false if the folder does not exist. // Note that npm packages are totally different from (normal) packages installed the OS's bundled package manager. They are node packages. export async function isNpmPackageInstalled(path, verbose = false) { try { const stdout = execSync('cd ' + folderPath + ' && npm list 2>&1') return true } catch(error) { const missingLocalPackagesCount = error.output.toString().match(/npm ERR! missing:/g).length || 0 if(missingLocalPackagesCount) { if(verbose) console.log(path, 'has', missingLocalPackagesCount, 'npm packages left to install.') } else { if(verbose) console.log('Error while checking if npm package at', path, 'is installed:', error) } } return false }