install.fairie/dotfiles/.local/share/chezmoi/home/dot_local/bin/executable_install-software

525 lines
19 KiB
Text
Raw Normal View History

#!/usr/bin/env zx
# Store data in YML file and then generate the data below with:
# yq e -o=j '.' .chezmoidata.yaml
let response = await fetch('https://gitlab.com/megabyte-labs/misc/dotfiles/-/raw/master/dotfiles/.local/share/chezmoi/software.json')
if (response.ok) {
const installData = await response.json()
} else {
await $`logg 'Error acquiring software installation map`
}
const installOrders = {}
const installOrdersPre = []
const installOrdersPost = []
const osType = OSType()
const osID = osType == 'linux' ? releaseID() : osType
### Creates the installOrders object which maps package managers to arrays of packages to install
function generateInstallOrders() {
const packagesToInstall = process.argv.slice(1)
const preferenceOrder = installData.installerPreference[OSTypeInstallerKey()]
const softwarePackages = installData.softwarePackages
for(let package of packagesToInstall) {
if (softwarePackages[package + ':' osID]) {
const packageKey = package + ':' + osID
} else if (softwarePackages[package + ':' + osType]) {
const packageKey = package + ':' + osType
} else if (softwarePackages[package]) {
const packageKey = package
} else {
$`logg '\`'"${package}'\` not found in the installation map'`
continue
}
$`logg '\`'"${package}'\` found in the installation map using \`'"${packageKey}"'\`'`
for (let preference of preferenceOrder) {
if (softwarePackages[packageKey][preference + ':' + osID]) {
updateInstallMaps(preference, softwarePackages[packageKey], preference + ':' + osID)
} else if (softwarePackages[packageKey][preference + ':' + osType]) {
updateInstallMaps(preference, softwarePackages[packageKey], preference + ':' + osType)
} else if (softwarePackages[packageKey][preference]) {
updateInstallMaps(preference, softwarePackages[packageKey], preference)
}
}
}
return installOrders
}
### Update install, pre-hook, and post-hook objects
function updateInstallMaps(preference, packages, scopedPreference) {
const preHook = getHook(packages, 'pre', scopedPreference, preference)
if (preHook) {
installOrdersPre.concat(typeof preHook === 'string' ? [preHook] : preHook)
}
const postHook(packages, 'post', scopedPreference, preference)
if (postHook) {
installOrdersPost.concat(typeof postHook === 'string' ? [postHook] : postHook)
}
if (!installOrders[preference]) {
installOrders[preference] = []
}
const newPackages = packages[scopedPreference]
installOrders[preference].concat(typeof newPackages === 'string' ? [newPackages] : newPackages)
}
### Get pre / post install hooks
function getHook(packages, hook, scopedPreference, preference) {
const hookLabel = '_' + hook + ':'
if (packages[hookLabel + scopedPreference]) {
return packages[hookLabel + scopedPreference]
} else if (packages[hookLabel + preference]) {
return packages[hookLabel + preference]
} else if (packages[hookLabel + osID]) {
return packages
} else if (packages[hookLabel + osType]) {
return packages[hookLabel + osType]
} else if (packages['_pre']) {
return packages['_pre']
}
}
### Acquire OS type installer key (for the installerPreference data key)
async function OSTypeInstallerKey() {
const osTypeKey = await $`
if [ -d /Applications ] && [ -d /Library ]; then
echo 'darwin'
elif command -v apt > /dev/null; then
echo 'apt'
elif command -v dnf > /dev/null; then
echo 'dnf'
elif command -v pacman > /dev/null; then
echo 'pacman'
elif command -v zypper > /dev/null; then
echo 'zypper'
elif command -v pkg > /dev/null; then
echo 'freebsd'
else
echo 'windows'
fi
`
return osTypeKey
}
### Acquire OS type
async function OSType() {
const osType = await $`
if [ -d /Applications ] && [ -d /Library ]; then
echo 'darwin'
elif [ -f /etc/os-release ]; then
echo 'linux'
else
echo 'windows'
fi
`
return osType
}
### Acquire release ID
async function releaseID() {
const ID = await $`
. /etc/os-release
echo $ID
`
return ID
}
### Post-install hook
async function afterInstall(packageManager) {
const PACKAGE_MANAGER = packageManager
await $`
if [ "$PACKAGE_MANAGER" = 'appimage' ]; then
elif [ "$PACKAGE_MANAGER" = 'apk' ]; then
elif [ "$PACKAGE_MANAGER" = 'apt' ]; then
elif [ "$PACKAGE_MANAGER" = 'basher' ]; then
elif [ "$PACKAGE_MANAGER" = 'binary' ]; then
elif [ "$PACKAGE_MANAGER" = 'bpkg' ]; then
elif [ "$PACKAGE_MANAGER" = 'brew' ]; then
elif [ "$PACKAGE_MANAGER" = 'cargo' ]; then
elif [ "$PACKAGE_MANAGER" = 'cask' ]; then
elif [ "$PACKAGE_MANAGER" = 'choco' ]; then
elif [ "$PACKAGE_MANAGER" = 'crew' ]; then
elif [ "$PACKAGE_MANAGER" = 'dnf' ]; then
elif [ "$PACKAGE_MANAGER" = 'flatpak' ]; then
elif [ "$PACKAGE_MANAGER" = 'gem' ]; then
elif [ "$PACKAGE_MANAGER" = 'go' ]; then
elif [ "$PACKAGE_MANAGER" = 'nix' ]; then
elif [ "$PACKAGE_MANAGER" = 'npm' ]; then
elif [ "$PACKAGE_MANAGER" = 'pacman' ]; then
elif [ "$PACKAGE_MANAGER" = 'pkg' ]; then
elif [ "$PACKAGE_MANAGER" = 'port' ]; then
elif [ "$PACKAGE_MANAGER" = 'scoop' ]; then
elif [ "$PACKAGE_MANAGER" = 'snap' ]; then
elif [ "$PACKAGE_MANAGER" = 'whalebrew' ]; then
elif [ "$PACKAGE_MANAGER" = 'winget' ]; then
elif [ "$PACKAGE_MANAGER" = 'yay' ]; then
elif [ "$PACKAGE_MANAGER" = 'zypper' ]; then
fi
`
}
### Pre-install hook
async function beforeInstall(packageManager) {
const PACKAGE_MANAGER = packageManager
await $`
if [ "$PACKAGE_MANAGER" = 'appimage' ]; then
elif [ "$PACKAGE_MANAGER" = 'apk' ]; then
elif [ "$PACKAGE_MANAGER" = 'apt' ]; then
sudo apt-get update
elif [ "$PACKAGE_MANAGER" = 'basher' ]; then
elif [ "$PACKAGE_MANAGER" = 'binary' ]; then
elif [ "$PACKAGE_MANAGER" = 'bpkg' ]; then
elif [ "$PACKAGE_MANAGER" = 'brew' ]; then
elif [ "$PACKAGE_MANAGER" = 'cargo' ]; then
elif [ "$PACKAGE_MANAGER" = 'cask' ]; then
elif [ "$PACKAGE_MANAGER" = 'choco' ]; then
elif [ "$PACKAGE_MANAGER" = 'crew' ]; then
elif [ "$PACKAGE_MANAGER" = 'dnf' ]; then
elif [ "$PACKAGE_MANAGER" = 'flatpak' ]; then
elif [ "$PACKAGE_MANAGER" = 'gem' ]; then
elif [ "$PACKAGE_MANAGER" = 'go' ]; then
elif [ "$PACKAGE_MANAGER" = 'nix' ]; then
elif [ "$PACKAGE_MANAGER" = 'npm' ]; then
elif [ "$PACKAGE_MANAGER" = 'pacman' ]; then
elif [ "$PACKAGE_MANAGER" = 'pkg' ]; then
elif [ "$PACKAGE_MANAGER" = 'port' ]; then
elif [ "$PACKAGE_MANAGER" = 'scoop' ]; then
elif [ "$PACKAGE_MANAGER" = 'snap' ]; then
elif [ "$PACKAGE_MANAGER" = 'whalebrew' ]; then
elif [ "$PACKAGE_MANAGER" = 'winget' ]; then
elif [ "$PACKAGE_MANAGER" = 'yay' ]; then
elif [ "$PACKAGE_MANAGER" = 'zypper' ]; then
fi
`
}
### Ensure the package manager is available
async function ensurePackageManager(packageManager) {
const PACKAGE_MANAGER = packageManager
await $`
### Ensures Homebrew is installed
ensurePackageManagerHomebrew() {
if ! command -v brew > /dev/null; then
if command -v sudo > /dev/null && sudo -n true; then
echo | bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
else
logg info 'Homebrew is not installed. Password may be required.'
bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || BREW_EXIT_CODE="$?"
if [ -n "$BREW_EXIT_CODE" ]; then
if command -v brew > /dev/null; then
logg warn 'Homebrew was installed but part of the installation failed. Attempting to fix..'
BREW_DIRS="share/man share/doc share/zsh/site-functions etc/bash_completion.d"
for BREW_DIR in $BREW_DIRS; do
if [ -d "$(brew --prefix)/$BREW_DIR" ]; then
sudo chown -R "$(whoami)" "$(brew --prefix)/$BREW_DIR"
fi
done
brew update --force --quiet
fi
fi
fi
fi
}
if [ "$PACKAGE_MANAGER" = 'appimage' ]; then
# Do nothing
elif [ "$PACKAGE_MANAGER" = 'apk' ]; then
if command -v apk > /dev/null; then
logg '`apk` is available'
else
logg error '`apk` is not installed' && exit 102
fi
elif [ "$PACKAGE_MANAGER" = 'apt' ]; then
if command -v apt > /dev/null; then
logg '`apt` is available'
else
logg error '`apt` is not installed' && exit 103
fi
elif [ "$PACKAGE_MANAGER" = 'basher' ]; then
if command -v basher > /dev/null; then
logg '`basher` is available'
else
# TODO - Install basher
fi
elif [ "$PACKAGE_MANAGER" = 'binary' ]; then
# Do nothing
elif [ "$PACKAGE_MANAGER" = 'bpkg' ]; then
if command -v bpkg > /dev/null; then
logg '`bpkg` is available'
else
# TODO - Install bpkg
fi
elif [ "$PACKAGE_MANAGER" = 'brew' ] || [ "$PACKAGE_MANAGER" = 'cask' ]; then
if command -v brew > /dev/null; then
logg '`brew` is available'
else
ensurePackageManagerHomebrew
fi
elif [ "$PACKAGE_MANAGER" = 'cargo' ]; then
if command -v cargo > /dev/null; then
logg '`cargo` is available'
else
# TODO - Install Cargo via Homebrew based method
fi
elif [ "$PACKAGE_MANAGER" = 'choco' ]; then
if command -v choco > /dev/null; then
logg '`choco` is available'
else
logg 'Installing Chocolatey'
powershell "Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))"
fi
elif [ "$PACKAGE_MANAGER" = 'crew' ]; then
if command -v crew > /dev/null; then
logg '`crew` is available'
else
# Source: https://github.com/chromebrew/chromebrew
curl -Ls git.io/vddgY | bash
fi
elif [ "$PACKAGE_MANAGER" = 'dnf' ]; then
if command -v dnf > /dev/null; then
logg '`dnf` is available'
elif command -v yum > /dev/null; then
logg '`yum` is available'
else
logg 'Both `dnf` and `yum` are not available' && exit 110
fi
elif [ "$PACKAGE_MANAGER" = 'flatpak' ]; then
if command -v flatpak > /dev/null; then
logg '`flatpak` is available'
else
ensurePackageManagerHomebrew
fi
elif [ "$PACKAGE_MANAGER" = 'gem' ]; then
if command -v gem > /dev/null; then
logg '`gem` is available'
else
ensurePackageManagerHomebrew
# TODO - is this enough to make `gem install` available?
brew install ruby
fi
elif [ "$PACKAGE_MANAGER" = 'go' ]; then
if command -v go > /dev/null; then
logg '`go` is available'
else
ensurePackageManagerHomebrew
brew install go
fi
elif [ "$PACKAGE_MANAGER" = 'nix' ]; then
if command -v nix > /dev/null; then
logg '`nix` is available'
elif [ -d /Applications ] && [ -d /Library ]; then
# macOS
sh <(curl -L https://nixos.org/nix/install)
else
# Linux
sh <(curl -L https://nixos.org/nix/install) --daemon
fi
elif [ "$PACKAGE_MANAGER" = 'npm' ]; then
if command -v volta > /dev/null && command -v npm > /dev/null && command -v node > /dev/null; then
logg '`volta`, `npm`, and `node` are all available'
else
if ! command -v volta > /dev/null; then
ensurePackageManagerHomebrew
if ! command -v volta > /dev/null; then
logg 'Installing `volta` via `brew`'
brew install volta
fi
logg 'Ensuring `node` and `npm` are installed using `volta`'
if [ -z "$VOLTA_HOME" ]; then
volta setup
fi
export PATH="$VOLTA_HOME/bin:$PATH"
volta install node
fi
fi
elif [ "$PACKAGE_MANAGER" = 'pacman' ]; then
if command -v pacman > /dev/null; then
logg '`pacman` is available'
else
logg '`pacman` is not installed' && exit 106
fi
elif [ "$PACKAGE_MANAGER" = 'pkg' ]; then
if command -v pkg > /dev/null; then
logg '`pkg` is available'
else
logg '`pkg` is not installed' && exit 107
elif [ "$PACKAGE_MANAGER" = 'port' ]; then
if command -v port > /dev/null; then
logg '`port` is available'
else
# TODO - Install port on macOS
fi
elif [ "$PACKAGE_MANAGER" = 'scoop' ]; then
if command -v scoop > /dev/null; then
logg '`scoop` is available'
else
# TODO - does this work? can we run PowerShell in a bash script?
powershell 'Set-ExecutionPolicy RemoteSigned -Scope CurrentUser'
powershell 'irm get.scoop.sh | iex'
fi
elif [ "$PACKAGE_MANAGER" = 'snap' ]; then
if command -v snap > /dev/null; then
logg '`snap` is available'
else
logg 'Installing `snap` via system package manager'
if command -v apt > /dev/null; then
# Source: https://snapcraft.io/docs/installing-snap-on-linux-mint
if [ -f /etc/apt/preferences.d/nosnap.pref ]; then
sudo mv /etc/apt/preferences.d/nosnap.pref /etc/apt/nosnap.pref.bak
fi
sudo apt install -y snapd
# TODO: Following may be required on Kali -> https://snapcraft.io/docs/installing-snap-on-kali
# systemctl enable --now snapd apparmor
elif command -v dnf > /dev/null; then
sudo dnf install -y snapd
if [ ! -d /snap ]; then
sudo ln -s /var/lib/snapd/snap /snap
fi
elif command -v yum > /dev/null; then
sudo yum install -y snapd
sudo systemctl enable --now snapd.socket
if [ ! -d /snap ]; then
sudo ln -s /var/lib/snapd/snap /snap
fi
elif command -v pacman > /dev/null; then
if [ -f /etc/arch-release ]; then
sudo git clone https://aur.archlinux.org/snapd.git /usr/local/src/snapd
cd /usr/local/src/snapd
sudo makepkg -si
else
sudo pacman -S snapd
sudo systemctl enable --now snapd.socket
if [ ! -d /snap ]; then
sudo ln -s /var/lib/snapd/snap /snap
fi
fi
elif command -v zypper > /dev/null; then
# TODO: See https://snapcraft.io/docs/installing-snap-on-opensuse
else
logg 'Could not find a package manager to install `snap` with'
fi
if command -v snap > /dev/null; then
logg 'Ensuring latest `snap` is available by running `sudo snap install core`'
sudo snap install core
fi
fi
elif [ "$PACKAGE_MANAGER" = 'whalebrew' ];
if command -v whalebrew > /dev/null; then
logg '`whalebrew` is available'
else
ensurePackageManagerHomebrew
logg 'Installing `whalebrew` via `brew`'
brew install whalebrew
fi
elif [ "$PACKAGE_MANAGER" = 'winget' ]; then
# TODO
elif [ "$PACKAGE_MANAGER" = 'yay' ]; then
if command -v yay > /dev/null; then
logg '`yay` is available'
else
logg 'Installing `yay` requirements'
sudo pacman -S --needed base-devel git
if [ -d /usr/local/src ]; then
logg 'Cloning `yay` source code to `/usr/local/src/yay`'
git clone https://aur.archlinux.org/yay.git /usr/local/src/yay
cd /usr/local/src/yay
makepkg -si
logg '`yay` installed`
else
logg error '`/usr/local/src` is not present on the system' && exit 105
fi
fi
elif [ "$PACKAGE_MANAGER" = 'zypper' ]; then
if command -v zypper > /dev/null; then
logg '`zypper` is available'
else
logg '`zypper` is not installed' && exit 104
fi
fi
`
}
### Installs a list of packages via the specified package manager
async function installPackageList(packageManager, packages) {
const PACKAGE_MANAGER = packageManager
const PACKAGES = packages
await $`
logg 'Installing '"${PACKAGES}"' via `'"${PACKAGE_MANAGER}"'`'
if [ "$PACKAGE_MANAGER" = 'appimage' ]; then
elif [ "$PACKAGE_MANAGER" = 'apk' ]; then
sudo apk add ${PACKAGES}
elif [ "$PACKAGE_MANAGER" = 'apt' ]; then
sudo apt-get install -y ${PACKAGES}
elif [ "$PACKAGE_MANAGER" = 'basher' ]; then
elif [ "$PACKAGE_MANAGER" = 'binary' ]; then
elif [ "$PACKAGE_MANAGER" = 'bpkg' ]; then
elif [ "$PACKAGE_MANAGER" = 'brew' ]; then
brew install ${PACKAGES}
elif [ "$PACKAGE_MANAGER" = 'cargo' ]; then
elif [ "$PACKAGE_MANAGER" = 'cask' ]; then
brew install --cask ${PACKAGES}
elif [ "$PACKAGE_MANAGER" = 'choco' ]; then
choco install -y ${choco}
elif [ "$PACKAGE_MANAGER" = 'crew' ]; then
elif [ "$PACKAGE_MANAGER" = 'dnf' ];
if command -v dnf > /dev/null; then
dnf install -y ${PACKAGES}
elif command -v yum > /dev/null; then
yum install -y ${PACKAGES}
else
logg warn 'Both `dnf` and `yum` are not present on the system'
fi
elif [ "$PACKAGE_MANAGER" = 'flatpak' ]; then
elif [ "$PACKAGE_MANAGER" = 'gem' ]; then
gem install ${PACKAGES}
elif [ "$PACKAGE_MANAGER" = 'go' ]; then
for GO_PACKAGE in ${PACKAGES}; do
go install "$GO_PACKAGE"
elif [ "$PACKAGE_MANAGER" = 'nix' ]; then
# TODO
elif [ "$PACKAGE_MANAGER" = 'npm' ]; then
volta install ${PACKAGES}
elif [ "$PACKAGE_MANAGER" = 'pacman' ]; then
sudo pacman -Sy --noconfirm --needed ${PACKAGES}
elif [ "$PACKAGE_MANAGER" = 'pkg' ]; then
# TODO
elif [ "$PACKAGE_MANAGER" = 'port' ]; then
sudo port install ${PACKAGES}
elif [ "$PACKAGE_MANAGER" = 'scoop' ]; then
scoop install ${PACKAGES}
elif [ "$PACKAGE_MANAGER" = 'snap' ]; then
sudo snap install -y ${PACKAGES}
elif [ "$PACKAGE_MANAGER" = 'whalebrew' ]; then
elif [ "$PACKAGE_MANAGER" = 'winget' ]; then
elif [ "$PACKAGE_MANAGER" = 'yay' ]; then
elif [ "$PACKAGE_MANAGER" = 'zypper' ]; then
fi
`
}
async function main() {
const installOrders = generateInstallOrders()
const packageManagers = Object.keys(installOrders)
for (const packageManager of packageManagers) {
await ensurePackageManager(packageManager)
}
for (const packageManager of packageManagers) {
await beforeInstall(packageManager)
}
for (const script of installOrdersPre) {
await $`${script}`
}
for (const packageManager of packageManagers) {
const asyncOrders = []
asyncOrders.push(Promise.resolve(installPackageList(packageManager, installOrders[packageManager])))
await Promise.all(asyncOrders)
}
for (const script of installOrdersPost) {
await $`${script}`
}
for (const packageManager of packageManagers) {
await afterInstall(packageManager)
}
}
main()