#!/usr/bin/env sh # set -x # Allows to install software # Find list of available installers in order of preference # Read wanted packages and their availability # Install packages per installer (after prompting) # COMMON FUNCTIONS # GLOBAL VARIABLES # TODO Lock or temp folder CACHE_DIR="${XDG_CACHE_DIR:-$HOME/.cache}/installSoftware" INSTALLERS_DIR="${CACHE_DIR}/installers" INSTALLERS_LIST="${CACHE_DIR}/installers.list" # TODO Package groups # INSTALLER SPECIFIC FUNCTIONS # Test if available available_pkgbuild() { true } available_Tapt() { [ -f /data/data/com.termux/files/usr/bin/apt ] } # Update the database update_Rpacman() { sudo pacman -Syu --noconfirm } update_Ryay() { yay -Syu --noconfirm --devel } update_Rapt() { # TODO non-interactive sudo apt update -y sudo apt upgrade -y } # Test if installed installed_Rpacman() { # packageName pacman -Qq "$1" &> /dev/null } installed_Ryay() { # package installed_Rpacman "$@" } installed_pip() { # package pip show "$@" > /dev/null } installed_makepkg() { # package installed_Rpacman "$@" } installed_pkgbuild() { # package installed_Rpacman "$@" # TODO Might need all the systems package too } installed_apt() { # package dpkg -s "$1" &> /dev/null } # Test if available in the repositories installable_aur() { curl --fail --silent --head "https://aur.archlinux.org/packages/$@" > /dev/null } installable_Rpacman() { pacman -Si "$1" &> /dev/null } installable_Ryay() { # yay -Ss "$1" > /dev/null installable_aur } installable_pkgbuild() { installable_aur } installable_makepkg() { installable_aur } installable_apt() { apt-cache show "$1" &> /dev/null } # Tell if it hadles mutiple argument for install multiinstall_pacman() { true } multiinstall_pip() { true } multiinstall_apt() { true } # Really install install_Rpacman() { sudo pacman -S --needed --noconfirm $@ } install_Ryay() { yay -S --needed --noconfirm $@ } install_Tapt() { apt install -y $@ } install_Rapt() { sudo apt install -y $@ } install_Rpip() { sudo pip install $@ } install_Upip() { pip install --user $@ } installable_Rmakepkg() { old_pwd="$PWD" TMP_DIR="$(mktemp -d /tmp/pkgbuild.XXXXXXXXXX)" cd "$TMP_DIR" wget "https://aur.archlinux.org/cgit/aur.git/snapshot/$1.tar.gz" tar xzvf "$1.tar.gz" cd "$1" makepkg -si cd "$old_pwd" rm -rf "$TMP_DIR" } # GENERIC INSTALLER FUNCTIONS installerCanonicalName() { # installerName echo "${1:1}" } notImplementedFallback() { # command installerName echo "[NIMPL] Not implemented: command $1_$2" false } # Wrapper to run a command for an installer commandInstaller() { # command installerName fallback args... # echo "[DEBUG] commandInstaller $*" command="$1" installerName="$2" fallback="$3" shift; shift; shift installerCName="$(installerCanonicalName "$installerName")" if command -v "${command}_$installerName" > /dev/null then "${command}_$installerName" "$@" elif command -v "${command}_$installerCName" > /dev/null then "${command}_$installerCName" "$@" else $fallback "$command" "$installerName" "$@" fi } # INSTALLER LIST FUNCTIONS availableInstallerFallback() { # command installerName command -v "$(installerCanonicalName "$2")" > /dev/null } availableInstaller() { # installerName commandInstaller "available" "$1" availableInstallerFallback } # Clears the list of installers to use resetInstallers() { rm -f "$INSTALLERS_LIST" touch "$INSTALLERS_LIST" rm -rf "$INSTALLERS_DIR" mkdir -p "$INSTALLERS_DIR" } addInstaller() { # installername if availableInstaller "$1" then echo "$1" >> "$INSTALLERS_LIST" rm -f "$INSTALLERS_DIR/$1" touch "$INSTALLERS_DIR/$1" return 0 fi return 1 } listInstallers() { cat "$INSTALLERS_LIST" } hasInstaller() { # installerName [ -f "${INSTALLERS_DIR}/$1" ] } # Installers that install in the user directory addUserInstallers() { addInstaller Tapt # Termux addInstaller Umakepkg addInstaller Upip # addInstaller Upkgbuild } # Installers that install with the system package manager addSystemInstallers() { addInstaller Rapt addInstaller Rpacman addInstaller Ryay || addInstaller Rmakepkg } # Installers that install in the system root but not tracked with system package manager addRootInstallers() { addInstaller Rnode addInstaller Rpip addInstaller Rpkgbuild } # UPDATING INSTALLER DATABASES updateInstallers() { for installerName in $(listInstallers) do commandInstaller "update" "$installerName" true done } # MARKING PACKAGES TO INSTALL markPackage() { # installer package # echo "[DEBUG] Marked $*" echo "$2" >> "$INSTALLERS_DIR/$1" } # Test if a package is installed installedPackage() { # package for installerName in $(listInstallers) do if commandInstaller "installed" "$installerName" notImplementedFallback "$1" then return 0 fi done return 1 } installablePackageBy() { # installer package commandInstaller "installable" "$1" notImplementedFallback "$2" } # List packages to install by given installer listPackagesForInstaller() { # installer cat "$INSTALLERS_DIR/$1" } isToInstall() { # package for installerName in $(listInstallers) do listPackagesForInstaller "$installerName" | grep -q "^$1\$" && return 0 done return 1 } # Mark package to installer list where available tryPackage() { # packageNames # If package is already installed or marked to install, skip for package in "$@" do installedPackage "$package" && return 0 isToInstall "$package" && return 0 done # For each installer for installerName in $(listInstallers) do # For each name given for package in "$@" do # Mark if name available to installer if installablePackageBy "$installerName" "$package" then markPackage "$installerName" "$package" return 0 fi done done echo "[ERR] Cannot install package with aliases: $*" return 1 } i() { tryPackage "$@" } installPackages() { for installerName in $(listInstallers) do # If we can install multiple packages in one go if commandInstaller "multiinstall" "$installerName" false then packages=$(listPackagesForInstaller "$installerName") [ -z "$packages" ] && continue commandInstaller "install" "$installerName" notImplementedFallback $packages else for packageName in $(listPackagesForInstaller "$installerName") do commandInstaller "install" "$installerName" notImplementedFallback "$packageName" done fi done }