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.
197 lines
6.4 KiB
197 lines
6.4 KiB
// 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. |
|
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 |
|
} |