Created
September 12, 2018 08:22
-
-
Save l3laze/f89e99672875f4e40b0b200d8393cc4b to your computer and use it in GitHub Desktop.
Package-manager-like tool for commands, memba?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# | |
# Memba - A "package manager" for global and local commands. | |
# | |
# Follows the suggested exit code range of 0 & 64-113 from http://www.tldp.org/LDP/abs/html/exitcodes.html | |
# | |
# | Exit Code | Meaning | | |
# | --- | --- | | |
# | 64 | Error -- no command | | |
# | 65 | Error -- unknown command | | |
# | 66 | Error -- no target pattern for remove/rm/- or remove-all/rma | | |
# | 67 | Error -- no command for add/+ | | |
# | 67 | Error -- command already exists | | |
set -e # Enable "exit on first error" | |
#-------------------------------------------- | |
# Utility functions memba? | |
# | |
# Based on https://stackoverflow.com/a/3232082/7665043 | |
confirm() { | |
# call with a prompt string or use a default | |
read -r -p "${1:-Are you sure? [y/N]} " response | |
case "$response" in | |
[yY][eE][sS]|[yY]) | |
echo 0 | |
;; | |
*) | |
echo 1 | |
;; | |
esac | |
} | |
# Based on https://stackoverflow.com/a/3951175/7665043 | |
function isNumber () { | |
case $1 in | |
''|*[!0-9]*) echo 1 ;; | |
*) echo 0 ;; | |
esac | |
} | |
function joinArray () { | |
echo "${@}" | |
} | |
# Based on https://stackoverflow.com/a/17841619/7665043 | |
function joinBy { | |
local d=$1 | |
shift | |
echo -n "$1" | |
shift | |
printf "%s" "${@/#/$d}" | |
} | |
# Based on https://stackoverflow.com/a/39463371/7665043 | |
expand-q () { | |
for i; do | |
printf "%s " "${i@Q}" | |
done | |
echo | |
} | |
#-------------------------------------------- | |
# Functions, memba? | |
# | |
function membaUsage () { | |
echo "Don't you memba...?" | |
} | |
function membaAdd () { | |
local membaConfig="$1" | |
local exists="false" | |
shift | |
[[ "$1" == "" ]] && echo "There must be a commands provided as a non-empty string provided for add/+." && membaUsage && exit 67 | |
[[ $(grep -c "^$1$" "$membaConfig") != "0" ]] && exists="true" | |
[[ "$exists" == "true" ]] && echo "\"$1\" already exists, memba?" && exit 68 | |
while [[ "$#" -gt 0 ]]; do | |
echo "${@}" >> "$membaConfig" | |
shift | |
done | |
} | |
function membaList () { | |
local membaConfig="$1" | |
shift | |
if [[ "$#" -ne 0 ]]; then | |
local pattern="$1" | |
grep "$pattern" "$membaConfig" | |
else | |
cat "$membaConfig" | |
fi | |
} | |
function membaListNumbered () { | |
membaList "$@" | nl -n ln -w 1 -s " " | |
} | |
function membaChoice () { | |
local membaConfig="$1" | |
local pattern | |
local choicesMemba | |
local choicesLen | |
local inp | |
local choiceMessage | |
local chosen | |
local membad | |
local target | |
shift | |
target=$(joinArray "${@}") | |
choicesMemba=$(membaListNumbered "$membaConfig" "$@") | |
choicesLen=$(echo "$choicesMemba" | tail -n 1 | awk '{ print $1 }') | |
[[ "$choicesLen" -eq 0 ]] && echo "There's no commands with \"$target\", memba?" && exit 0 | |
membad=$(if [[ "$target" != "" ]]; then | |
printf "I memba %sx command" "$choicesLen" | |
[[ "$#" -gt 1 ]] && printf "s" | |
echo " with \"$target\"." | |
else | |
printf "I memba %sx command" "$choicesLen" | |
[[ "$#" -gt 1 ]] && printf "s" | |
echo "." | |
fi) | |
choiceMessage=$(echo -e "$membad\n--------\n$choicesMemba\n\n--------\nChoose a command by number or 0 to cancel, memba?\nChoice: ") | |
while [[ -z "$inp" || $(isNumber "$inp") -eq 1 || "$inp" -lt 0 || "$inp" -gt $choicesLen ]]; do | |
clear > "$(tty)" | |
[[ "$inp" != "" ]] && echo -e "$inp is not a choice, memba?\n" | |
read -r -p "$choiceMessage" inp | |
inp=$(echo "$inp" | tr -d '[:space:]') | |
done | |
if [[ "$inp" -ne 0 ]]; then | |
chosen=$(echo "$choicesMemba" | awk '$1 == inp { for(i=2;i<=NF;++i) print $i }' inp="$inp" | tr '\n' ' ') | |
else | |
chosen="cancel" | |
fi | |
if [[ "$chosen" != "cancel" ]]; then | |
$chosen || echo "That command is broken, memba?" | |
fi | |
} | |
function membaRemove () { | |
local membaConfig="$1" | |
local matches | |
local count=0 | |
local target | |
local message | |
local newConfig | |
shift | |
target=$(joinArray "${@}") | |
[[ "$target" == "" ]] && echo "There must be a pattern provided as a non-empty string for remove-all/rma, memba?" && membaUsage && exit 66 | |
matches=$(grep "$target" "$membaConfig") | |
count=$(grep -c "$target" "$membaConfig") | |
[[ "$count" -lt 1 ]] && echo "No, I don't memba \"$target\".." && exit 68 | |
message=$(echo -e "Are you sure you want to remove all commands containing \"$target\"?\n${matches}\n[y/N], memba?:") | |
echo "I memba ""$count""x command" | |
[[ "$#" -gt 1 ]] && printf "s" | |
" with \"$target\"." | |
if [[ "$count" -ne 0 && $(confirm "$message") -eq 0 ]]; then | |
newConfig=$(awk '!/'"$target"'/ { print }' < "$membaConfig") | |
[[ "$newConfig" == "" ]] && printf "" > "$membaConfig" || echo "$newConfig" > "$membaConfig" | |
fi | |
} | |
#-------------------------------------------- | |
# Parse args and run, memba!? | |
# | |
function runScript () { | |
local membaConfig="$HOME/.memba" | |
if [[ "$#" -eq 0 ]]; then | |
# Display usage.. | |
echo "This needs a command, memba?" | |
membaUsage | |
exit 64 | |
else | |
local option="$1" | |
shift | |
case $option in | |
"add" | "+" ) | |
membaAdd "$membaConfig" "$@" | |
;; | |
"choice" | "ch" | "?" ) | |
membaChoice "$membaConfig" "$@" | |
;; | |
"list" | "ls" | "." ) | |
membaList "$membaConfig" "$@" | |
;; | |
"remove" | "rm" | "-" ) | |
membaRemove "$membaConfig" "$@" | |
;; | |
* ) | |
echo "Unknown command \"$option\", memba?" | |
membaUsage | |
exit 66 | |
esac | |
fi | |
} | |
calledWith=$(expand-q $(ps -o args= $$ | awk '{ for(i=4;i<=NF;++i) print $i }' )) | |
echo "$calledWith" | |
runScript "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment