|
|
|
#!/bin/sh
|
|
|
|
# Bare Metal Alchemist, 2022
|
|
|
|
|
|
|
|
#############################################
|
|
|
|
# Lead - ♄ #
|
|
|
|
#############################################
|
|
|
|
|
|
|
|
# The most basic ingredient in an Alchemy recipe, lead is used in all
|
|
|
|
# recipes in this repository to standardize some simple things that I
|
|
|
|
# rely on to make scripts concise and pleasant to use
|
|
|
|
|
|
|
|
# --------------- Escape Codes ---------------
|
|
|
|
# These constants are used to add color and text formatting to the
|
|
|
|
# terminal's output -- Further reading: ANSI Escape Codes
|
|
|
|
RED="\e[0;31m"
|
|
|
|
GREEN="\e[0;32m"
|
|
|
|
BLUE="\e[0;34m"
|
|
|
|
BOLD="\e[1m"
|
|
|
|
ITALIC="\e[3m"
|
|
|
|
ULINE="\e[4m"
|
|
|
|
RESET="\e[0m"
|
|
|
|
|
|
|
|
# TODO -- there are actually a lot of ANSI codes that can be used
|
|
|
|
# 0 - Reset (normal attributes)
|
|
|
|
# 1 - Bold or increased intensity
|
|
|
|
# 2 - Faint (opposite of bold)
|
|
|
|
# 3 - Italic
|
|
|
|
# 4 - Underline
|
|
|
|
# 5 - Blink slowly
|
|
|
|
# 6 - Blink quickly
|
|
|
|
# 7 - Swap foreground and background
|
|
|
|
# 8 - Conceal
|
|
|
|
# 9 - Cross-out
|
|
|
|
# 10 - Default font
|
|
|
|
# 11-19 - Alternate fonts
|
|
|
|
# 20 - Fraktur font
|
|
|
|
# 21 - Bold off or double underline
|
|
|
|
# 22 - Bold and faint off
|
|
|
|
# 23 - Italic and fraktur off
|
|
|
|
# 24 - Underline off
|
|
|
|
# 25 - Blink off
|
|
|
|
# 27 - Undo foreground and background swapping
|
|
|
|
# 28 - Conceal off
|
|
|
|
# 29 - Cross-out off
|
|
|
|
# 39 - Default text color
|
|
|
|
# 49 - Default background color
|
|
|
|
# 51 - Framed
|
|
|
|
# 52 - Encircled
|
|
|
|
# 53 - Overlined
|
|
|
|
# 54 - Frame and encircle off
|
|
|
|
# 55 - Overline off
|
|
|
|
|
|
|
|
# TODO -- these should be implemented as part of the syntax for "say"
|
|
|
|
|
|
|
|
# --------------- Traps ---------------
|
|
|
|
|
|
|
|
# Traps, in the case of shell scripting, listen for certain signals
|
|
|
|
# that are broadcast by the system and execute a command in response
|
|
|
|
|
|
|
|
# We only want these to activate if we're running a recipe, so we
|
|
|
|
# check to see if we're running a "shell inside of a shell"
|
|
|
|
if [[ $SHLVL -gt 1 ]]; then
|
|
|
|
# Make sure that ctrl+C consistently exits the script
|
|
|
|
trap "exit" INT
|
|
|
|
# Give informative error messages when we receive ERR
|
|
|
|
trap 'say "${RED}Oops...${RESET} Something went wrong on line $LINENO of this script. Exit code was $?" >&2' ERR
|
|
|
|
fi
|
|
|
|
|
|
|
|
# --------------- Functions ---------------
|
|
|
|
|
|
|
|
# Coding Moment: generally, whenever you see something with brackets
|
|
|
|
# at the end of it, like this() or like(this), it's a function!
|
|
|
|
# It takes inputs and gives (or does) something as an output
|
|
|
|
|
|
|
|
# --------------- Input/Output ---------------
|
|
|
|
|
|
|
|
# 'say' is a simple function that imitates "echo"
|
|
|
|
# This needs to be built out way more! Replace echo for POSIX compatibility
|
|
|
|
say() {
|
|
|
|
printf "%b\n" "${1}"
|
|
|
|
}
|
|
|
|
|
|
|
|
ask_for() {
|
|
|
|
if [ ${#} -eq 0 ]; then
|
|
|
|
say "To use this command, you need to pass the variable you want,"
|
|
|
|
say "and then add as string of text to ask for it if you want. Example:\n"
|
|
|
|
say "ask_for RESPONSE \"Could you give me a RESPONSE please?\""
|
|
|
|
say ""
|
|
|
|
say "Afterwards, you'll be able to use \$RESPONSE as a variable,"
|
|
|
|
say "and ${ITALIC}say \$RESPONSE${RESET} will respond with your entry"
|
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ -n "${2}" ]; then
|
|
|
|
printf "%b" "${2}"
|
|
|
|
fi
|
|
|
|
|
|
|
|
read ${1}
|
|
|
|
}
|
|
|
|
|
|
|
|
# --------------- Environment Setup ---------------
|
|
|
|
|
|
|
|
# If there's an env file, export it's contents to the environment
|
|
|
|
source_env() {
|
|
|
|
if [ -f .env ]; then
|
|
|
|
export $(grep -v '^#' .env | xargs)
|
|
|
|
else
|
|
|
|
if [ -z $ALCHEMY ]; then
|
|
|
|
say "No .env file, this might cause some issues..."
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
# This is how we call a function that we have already defined.
|
|
|
|
# This one takes no arguments (words after the function name
|
|
|
|
source_env
|
|
|
|
|
|
|
|
# --------------- Program Installation ---------------
|
|
|
|
|
|
|
|
# Checks to see if we can use a command or not
|
|
|
|
check_for() {
|
|
|
|
command -v "$1" >/dev/null
|
|
|
|
}
|
|
|
|
|
|
|
|
# This one installs utilities to your OS (If you need them!)
|
|
|
|
install_if_needed() {
|
|
|
|
for package in "$@" # $@ means "all the arguments you passed
|
|
|
|
do
|
|
|
|
case $DISTRO in
|
|
|
|
"debian")
|
|
|
|
# TODO Better installation detection than check_for
|
|
|
|
if [ -z $(check_for $package) ]; then
|
|
|
|
say "installing $package"
|
|
|
|
sudo apt install -y $package
|
|
|
|
else
|
|
|
|
say "$package already installed!"
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
"arch")
|
|
|
|
if pacman -Qi $package &>/dev/null; then
|
|
|
|
say "$package already installed!"
|
|
|
|
else
|
|
|
|
say "installing $package"
|
|
|
|
sudo pacman -S $package --noconfirm --needed
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
"fedora")
|
|
|
|
# TODO Better installation detection than "check_for"
|
|
|
|
if [ -z $(check_for $package) ]; then
|
|
|
|
say "installing $package"
|
|
|
|
sudo dnf install -y $package
|
|
|
|
else
|
|
|
|
say "$package already installed!"
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
"mac")
|
|
|
|
# TODO Better installation detection than "check_for"
|
|
|
|
if [ -z $(check_for $package) ]; then
|
|
|
|
say "installing $package"
|
|
|
|
brew install $package
|
|
|
|
else
|
|
|
|
say "$package already installed!"
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# --------------- Memory ---------------
|
|
|
|
# These two functions might look like gibberish because we're using regex,
|
|
|
|
# short for REGular EXpression. It's a form of matching text to a pattern.
|
|
|
|
|
|
|
|
|
|
|
|
# It takes values and stores them away in the env for later reference
|
|
|
|
forget() {
|
|
|
|
DOTENV_ENTRY=$(cat .env | grep ^${1}\=)
|
|
|
|
if [ -n "$DOTENV_ENTRY" ]; then
|
|
|
|
unset ${1}
|
|
|
|
sed -i "/^${1}.*$/d" .env
|
|
|
|
else
|
|
|
|
say "I already don't remember ${BLUE}${1}${RESET}..."
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Once we've made changes, we need to make sure we're up to date
|
|
|
|
source_env
|
|
|
|
}
|
|
|
|
|
|
|
|
remember() {
|
|
|
|
KEY=$(say ${1} | cut -d'=' -f 1)
|
|
|
|
VALUE=$(say ${1} | cut -d'=' -f 2)
|
|
|
|
|
|
|
|
if [[ ! $KEY =~ ^[A-Z_]+$ ]]; then
|
|
|
|
say "Keys must consist only of capital letters and underscores"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [[ ! $VALUE =~ ^[A-Za-z0-9/_.:]+$ ]]; then
|
|
|
|
say "Valid characters for env values: letters, numbers, \".\",\"/\",\"_\"",\":\"
|
|
|
|
fi
|
|
|
|
|
|
|
|
# If we're setting a valid key/value pair
|
|
|
|
if [[ ${1} =~ ^[A-Z_]+\=[A-Za-z0-9/._:]*$ ]]; then
|
|
|
|
|
|
|
|
DOTENV_ENTRY=$(cat .env | grep ${KEY})
|
|
|
|
# If something already exists and we're trying to set it to something new
|
|
|
|
if [ -n "$DOTENV_ENTRY" ] && [ "$DOTENV_ENTRY" != "$1" ]; then
|
|
|
|
say "I'm trying to remember ${BLUE}${1}${RESET}, but..."
|
|
|
|
say ""
|
|
|
|
say "${BLUE}${DOTENV_ENTRY}${RESET}"
|
|
|
|
say "This has already been defined in the .env file!"
|
|
|
|
say ""
|
|
|
|
ask_for overwrite "would you like to overwrite it? ${BLUE}(y/n)${RESET} "
|
|
|
|
case $overwrite in
|
|
|
|
"y" | "Y")
|
|
|
|
unset ${KEY}
|
|
|
|
sed -i "/^${KEY}.*$/d" .env
|
|
|
|
echo "${1}" >> .env
|
|
|
|
export ${1}
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
elif [ -z "$DOTENV_ENTRY" ]; then
|
|
|
|
unset ${KEY}
|
|
|
|
echo "${1}" >> .env
|
|
|
|
export ${1}
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Once we've made changes, we need to make sure we're up to date
|
|
|
|
source_env
|
|
|
|
}
|
|
|
|
|
|
|
|
LEAD=1
|